Java tutorial
/* * This file is part of SpongeAPI, licensed under the MIT License (MIT). * * Copyright (c) SpongePowered <https://www.spongepowered.org> * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.spongepowered.api.item.inventory; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.spongepowered.api.util.weighted.VariableAmount.baseWithRandomAddition; import static org.spongepowered.api.util.weighted.VariableAmount.fixed; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.spongepowered.api.data.DataTransactionResult; import org.spongepowered.api.data.key.Key; import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.data.manipulator.DataManipulator; import org.spongepowered.api.data.meta.ItemEnchantment; import org.spongepowered.api.data.value.BaseValue; import org.spongepowered.api.data.value.mutable.ListValue; import org.spongepowered.api.data.value.mutable.SetValue; import org.spongepowered.api.data.value.mutable.Value; import org.spongepowered.api.item.Enchantment; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.util.Tuple; import org.spongepowered.api.util.weighted.VariableAmount; import org.spongepowered.api.util.weighted.WeightedTable; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; /** * A factory for generating {@link BiConsumer}s to apply to an * {@link ItemStack.Builder}, usually through an {@link ItemStackGenerator}. * * <p>Note that the {@link BiConsumer}s are expected to utilize the passed in * {@link Random} and use the builder as necessary.</p> */ public final class ItemStackBuilderPopulators { /** * Creates a new {@link BiConsumer} to set the {@link ItemStack.Builder} * to use the provided {@link ItemStackSnapshot} as a "default". Note * that the normal behavior of the builder is to reset according to * the snapshot. * * @param snapshot The snapshot to set the builder to use * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> itemStack(ItemStackSnapshot snapshot) { checkNotNull(snapshot, "ItemStackSnapshot cannot be null!"); return (builder, random) -> builder.fromSnapshot(snapshot); } /** * Creates a new {@link BiConsumer} that uses a randomized selection * of the provided {@link ItemStackSnapshot}s. The builder, when called will * only use one at random selection to default to. * * @param snapshot The first snapshot * @param snapshots The additional snapshots * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> itemStacks(ItemStackSnapshot snapshot, ItemStackSnapshot... snapshots) { checkNotNull(snapshot, "ItemStackSnapshot cannot be null!"); final WeightedTable<ItemStackSnapshot> table = new WeightedTable<>(1); table.add(snapshot, 1); for (ItemStackSnapshot stackSnapshot : snapshots) { table.add(checkNotNull(stackSnapshot, "ItemStackSnapshot cannot be null!"), 1); } return (builder, random) -> builder.fromSnapshot(table.get(random).get(0)); } /** * Creates a new {@link BiConsumer} that defines the provided * {@link ItemType}. * * @param itemType The given item type * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> item(ItemType itemType) { checkNotNull(itemType, "ItemType cannot be null!"); return (builder, random) -> builder.itemType(itemType); } /** * Creates a new {@link BiConsumer} that defines the provided * {@link ItemType}, provided that the {@link Supplier} does not * return null. * * <p>Note that the {@link Supplier} is not queried for an * {@link ItemType} until the generated {@link BiConsumer} is * called.</p> * * @param supplier The supplier of the item type * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> item(Supplier<ItemType> supplier) { checkNotNull(supplier, "Supplier cannot be null!"); return (builder, random) -> builder .itemType(checkNotNull(supplier.get(), "Supplier returned a null ItemType")); } /** * Creates a new {@link BiConsumer} that provides a random * {@link ItemType} of the provided item types. * * <p>Note that the desired {@link ItemType} given to the builder is only * defined at the time of calling {@link BiConsumer#accept(Object, Object)}. * </p> * * @param itemType The first item type * @param itemTypes The additional item types * @return The new biconsumer to apply to an item stack builder */ public static BiConsumer<ItemStack.Builder, Random> items(ItemType itemType, ItemType... itemTypes) { return items(ImmutableList.<ItemType>builder().add(itemType).addAll(Arrays.asList(itemTypes)).build()); } /** * Creates a new {@link BiConsumer} that provides a random * {@link ItemType} from the provided collection of item types. * * @param itemTypes The item types to use * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> items(final Collection<ItemType> itemTypes) { final ImmutableList<ItemType> copiedItemTypes = ImmutableList.copyOf(itemTypes); return (builder, random) -> builder.itemType(copiedItemTypes.get(random.nextInt(copiedItemTypes.size()))); } /** * Creates a new {@link BiConsumer} that sets the desired quantity * for creating an {@link ItemStack}. * * <p>Note that the default behavior of the item stack builder is still * expected to take place. Negative values are not allowed.</p> * * @param amount The variable amount * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> quantity(VariableAmount amount) { checkNotNull(amount, "VariableAmount cannot be null!"); return (builder, random) -> builder.quantity(amount.getFlooredAmount(random)); } /** * Creates a new {@link BiConsumer} that sets the desired quantity * for creating an {@link ItemStack}. The supplier is not queried for * a {@link VariableAmount} until the generated bi consumer is * called on. * * <p>Note that the default behavior of an item stack builder is still * expected to take place. Negative values are not allowed.</p> * * @param supplier The supplier of the variable amount * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> quantity(Supplier<VariableAmount> supplier) { checkNotNull(supplier, "Supplier cannot be null!"); return (builder, random) -> builder.quantity(supplier.get().getFlooredAmount(random)); } /** * Creates a new {@link BiConsumer} that sets the provided {@link Key}'ed * object where the value is possibly ignored or not supported. No checks * on whether the key or object is supported until called upon. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param value The value to use * @param <E> The type of value * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> keyValue(Key<? extends BaseValue<E>> key, E value) { return (builder, random) -> { final ItemStack itemStack = builder.build(); final DataTransactionResult dataTransactionResult = itemStack.offer(key, value); if (dataTransactionResult.isSuccessful()) { builder.from(itemStack); } }; } /** * Creates a new {@link BiConsumer} that sets a single provided * value with the provided {@link Key}. Only a single value is chosen * to provide to the itemstack builder. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param values The pool of possible values * @param <E> The type of value * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> keyValues(Key<? extends BaseValue<E>> key, Iterable<E> values) { checkNotNull(values, "Iterable cannot be null!"); checkNotNull(key, "Key cannot be null!"); WeightedTable<E> tableEntries = new WeightedTable<>(1); for (E e : values) { tableEntries.add(checkNotNull(e, "Value cannot be null!"), 1); } return (builder, random) -> { final ItemStack itemStack = builder.build(); final DataTransactionResult dataTransactionResult = itemStack.offer(key, tableEntries.get(random).get(0)); if (dataTransactionResult.isSuccessful()) { builder.from(itemStack); } }; } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link List} based {@link Value}. Given that the provided elements * are chosent with a {@link Random}, it's not clear that the elements will * be added in bundles or in the same iteration order. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param elementPool The pool of possible values * @param amount The variable amount of elements to add * @param <E> The type of elements * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> listValues(Key<? extends ListValue<E>> key, List<E> elementPool, VariableAmount amount) { checkNotNull(key, "Key cannot be null!"); checkNotNull(elementPool, "Element pool cannot be null!"); checkNotNull(amount, "VariableAmount cannot be null!"); checkArgument(!elementPool.isEmpty(), "Element pool cannot be empty!"); WeightedTable<E> elementTable = new WeightedTable<>(amount); for (E element : elementPool) { elementTable.add(checkNotNull(element, "Element cannot be null!"), 1); } return listValues(key, elementTable); } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link List} based {@link Value}. Given that the provided elements * are chosent with a {@link Random}, it's not clear that the elements will * be added in bundles or in the same iteration order. The default variance * is provided as {@link VariableAmount#baseWithRandomAddition(double, double)} * where at the least, a single element is chosen, and at most the entire * collection is chosen. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param elementPool The pool of possible values * @param <E> The type of elements * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> listValues(Key<? extends ListValue<E>> key, List<E> elementPool) { return listValues(key, elementPool, baseWithRandomAddition(1, elementPool.size() - 1)); } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link List} based {@link Value}. Given the {@link WeightedTable} * is already generated, the values requested are only retrieved when * the generated biconsumer is called upon. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param weightedTable The weighted table * @param <E> The type of elements * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> listValues(Key<? extends ListValue<E>> key, WeightedTable<E> weightedTable) { checkNotNull(weightedTable, "Weighted table cannot be null!"); checkNotNull(key, "Key cannot be null!"); return setValue(key, random -> ImmutableList.copyOf(weightedTable.get(random))); } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link List} based {@link Value}. Given the * {@link WeightedTable} is exclusively used with {@link Function}s, * the {@link Function}s themselves are queried with a {@link Random} * and expected to present a singular element of the defined type. It's * expected that there are multiple functions to provide additional * elements for a particular key'ed {@link ListValue}. * * <p>An example usage of this can be for generating a randomized list * of {@link ItemEnchantment}s with varying enchantment levels.</p> * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param weightedTable The weighted table containing all the desired * functions producing the randomized elements * @param <E> The type of element * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> listValueSuppliers(Key<? extends ListValue<E>> key, WeightedTable<Function<Random, E>> weightedTable) { checkNotNull(key, "Key cannot be null!"); checkNotNull(weightedTable, "WeightedTable cannot be null!"); return (builder, random) -> { final ItemStack itemStack = builder.build(); final List<Function<Random, E>> suppliers = weightedTable.get(random); final List<E> suppliedElements = suppliers.stream() .map(randomEFunction -> randomEFunction.apply(random)).collect(Collectors.toList()); final DataTransactionResult result = itemStack.offer(key, suppliedElements); if (result.isSuccessful()) { builder.from(itemStack); } }; } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link Set} based {@link Value}. Given the {@link Set} of element * to act as a pool, the consumer will pull a random amount of the * given pool and apply it as a new {@link Set}. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param elementPool The set of elements to use as a pool * @param <E> The type of element * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> setValues(Key<? extends SetValue<E>> key, Set<E> elementPool) { checkNotNull(key, "Key cannot be null!"); checkNotNull(elementPool, "ElementPool cannot be null!"); return setValues(key, elementPool, baseWithRandomAddition(1, elementPool.size() - 1)); } /** * Creates a new {@link BiConsumer} where the {@link Key} is responsible * for a {@link Set} based {@link Value}. Given the {@link Set} of * elements to act as a pool, the consumer will pull a variable amount * based on the provided {@link VariableAmount}, and apply it as a new * {@link Set}. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param elementPool The set of elements to use as a pool * @param amount The variable amount of elements to get * @param <E> The type of element * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> setValues(Key<? extends SetValue<E>> key, Set<E> elementPool, VariableAmount amount) { checkNotNull(key, "Key cannot be null!"); checkNotNull(elementPool, "Element pool cannot be null!"); checkNotNull(amount, "VariableAmount cannot be null!"); checkArgument(!elementPool.isEmpty()); WeightedTable<E> elementTable = new WeightedTable<>(amount); for (E element : elementPool) { elementTable.add(element, 1); } return setValues(key, elementTable); } /** * Creates a new {@link BiConsumer} where the {@link Key} is * responsible for a {@link Set} based {@link Value}. Given * the provided {@link WeightedTable}, the consumer will retrieve * a {@link List} of values and add them as a new {@link Set}. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param key The key to use * @param weightedTable The weighted table acting as an element pool * @param <E> The type of element * @return The new biconsumer to apply to an itemstack builder */ public static <E> BiConsumer<ItemStack.Builder, Random> setValues(Key<? extends SetValue<E>> key, WeightedTable<E> weightedTable) { checkNotNull(weightedTable, "WeightedTable cannot be null!"); checkNotNull(key, "Key cannot be null!"); checkArgument(!weightedTable.isEmpty(), "WeightedTable cannot be empty!"); return setValue(key, random -> ImmutableSet.copyOf(weightedTable.get(random))); } /*Note : This is used interanlly only, no validation is performed.*/ private static <E> BiConsumer<ItemStack.Builder, Random> setValue(Key<? extends BaseValue<E>> key, Function<Random, E> element) { return (builder, random) -> { final ItemStack itemStack = builder.build(); final DataTransactionResult result = itemStack.offer(key, element.apply(random)); if (result.isSuccessful()) { builder.from(itemStack); } }; } /** * Creates a new {@link BiConsumer} that applies the provided {@link Value} * to the generated {@link ItemStack}. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param value The value to use * @param <E> The type of element * @param <V> The type of value * @return The new biconsumer to apply to an itemstack builder */ public static <E, V extends BaseValue<E>> BiConsumer<ItemStack.Builder, Random> value(V value) { return (builder, random) -> { final ItemStack itemStack = builder.build(); final DataTransactionResult dataTransactionResult = itemStack.offer(value); if (dataTransactionResult.isSuccessful()) { builder.from(itemStack); } }; } /** * Creates a new {@link BiConsumer} that applies a random selection of the * provided {@link BaseValue}s. * * <p>Note that custom data is not supported through this method, use * {@link #data(Collection)} or any variant thereof for applying custom data.</p> * * @param values The iterable collection of values to choose from * @param <E> The type of element * @param <V> The type of value * @return The new biconsumer to apply to an itemstack builder */ public static <E, V extends BaseValue<E>> BiConsumer<ItemStack.Builder, Random> values(Iterable<V> values) { WeightedTable<V> tableEntries = new WeightedTable<>(1); for (V value : values) { tableEntries.add(checkNotNull(value, "Value cannot be null!"), 1); } return ((builder, random) -> { final V value = tableEntries.get(random).get(0); final ItemStack itemStack = builder.build(); final DataTransactionResult result = itemStack.offer(value); if (result.isSuccessful()) { builder.from(itemStack); } }); } /** * Creates a new {@link BiConsumer} that sets a particular * {@link DataManipulator} onto an {@link ItemStack}. Note * that no validation can be performed, however the builder * will ignore unsupported data. This can be used to provide * custom data manipulators. * * @param manipulator The manipulator to apply to an itemstack * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> data(DataManipulator<?, ?> manipulator) { checkNotNull(manipulator, "DataManipulator cannot be null!"); return (builder, random) -> builder.itemData(manipulator); } /** * Creates a new {@link BiConsumer} that sets a single * {@link DataManipulator} form the provided collection of manipulators. * Note that no validation can be performed, however the builder will * ignore unsupported data. This can be used to provide custom data * manipulators. To apply multiple manipulators, use * {@link #data(Collection, VariableAmount)}. * * @param manipulators The pool of manipulators to use * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> data(Collection<DataManipulator<?, ?>> manipulators) { checkNotNull(manipulators, "DataManipulators cannot be null!"); final WeightedTable<DataManipulator<?, ?>> table = new WeightedTable<>(); manipulators .forEach(manipulator -> table.add(checkNotNull(manipulator, "DataManipulator cannot be null!"), 1)); return (builder, random) -> builder.itemData(table.get(random).get(0)); } /** * Creates a new {@link BiConsumer} that provides a {@link VariableAmount} * of {@link DataManipulator}s from the provided pool. Note that no * validation can be performed, however the builder will ignore unsupported * data. This can be used to provide custom data manipulators. * * @param manipulators The manipulator pool to use * @param rolls The variable amount of manipulators to apply * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> data(Collection<DataManipulator<?, ?>> manipulators, VariableAmount rolls) { checkNotNull(manipulators, "Manipulators cannot be null!"); checkNotNull(rolls, "VariableAmount cannot be null!"); final ImmutableList<DataManipulator<?, ?>> copied = ImmutableList.copyOf(manipulators); final WeightedTable<DataManipulator<?, ?>> table = new WeightedTable<>(); table.setRolls(rolls); copied.forEach(manipulator1 -> table.add(manipulator1, 1)); return data(table); } /** * Creates a new {@link BiConsumer} that provides a variable * amount of {@link DataManipulator}s from the provided * {@link WeightedTable}. Note that no validation can be performed, however * the builder will ignore unsupported data. This can be used to provide * custom data manipulators. * * @param weightedTable The weighted table containing manipulators * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> data(WeightedTable<DataManipulator<?, ?>> weightedTable) { checkNotNull(weightedTable, "WeightedTable cannot be null!"); return (builder, random) -> weightedTable.get(random).forEach(builder::itemData); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Enchantment} and applies it to the generated {@link ItemStack}. * The enchantment level is varied based on vanilla mechanics. * * @param enchantment The singular enchantment to add * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantment(Enchantment enchantment) { return enchantment(fixed(1), enchantment); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Enchantment} and applies it to the generated {@link ItemStack}. * The enchantment level is defined by the variable amount provided. * * @param level The variance in enchantment level * @param enchantment The enchantment to add * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantment(VariableAmount level, Enchantment enchantment) { checkNotNull(level, "VariableAmount cannot be null!"); checkNotNull(enchantment, "Enchantment cannot be null!"); return enchantments(fixed(1), ImmutableList.of(new Tuple<>(enchantment, level))); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Collection} of {@link Enchantment}s and applies a * singular {@link Enchantment} with varying levels to the generated * {@link ItemStack}. * * @param enchantments The enchantment pool to choose from * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantmentsWithVanillaLevelVariance( Collection<Enchantment> enchantments) { return enchantmentsWithVanillaLevelVariance(fixed(1), ImmutableList.copyOf(enchantments)); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Enchantment}s and applies a variable amount of enchantments * with varying levels to the generated {@link ItemStack}. * * @param amount The variable amount of enchantments to use * @param enchantment The first enchantment to add * @param enchantments The additional enchantments to use * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantmentsWithVanillaLevelVariance(VariableAmount amount, Enchantment enchantment, Enchantment... enchantments) { return enchantmentsWithVanillaLevelVariance(amount, ImmutableList.<Enchantment>builder().add(enchantment).addAll(Arrays.asList(enchantments)).build()); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Collection} of {@link Enchantment}s and applies a varying amount * of generated enchantments to the generated {@link ItemStack}. * * @param amount The varying amount of enchantments to use * @param itemEnchantments The enchantment pool to use * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantmentsWithVanillaLevelVariance(VariableAmount amount, Collection<Enchantment> itemEnchantments) { checkNotNull(amount, "Variable amount cannot be null!"); checkNotNull(itemEnchantments, "Enchantment collection cannot be null!"); List<Tuple<Enchantment, VariableAmount>> list = itemEnchantments.stream().map(enchantment -> { checkNotNull(enchantment, "Enchantment cannot be null!"); final int minimum = enchantment.getMinimumLevel(); final int maximum = enchantment.getMaximumLevel(); return new Tuple<>(enchantment, baseWithRandomAddition(minimum, maximum - minimum)); }).collect(Collectors.toList()); return enchantments(amount, list); } /** * Creates a new {@link BiConsumer} that takes the provided * {@link Collection} of coupled {@link Enchantment} and * {@link VariableAmount} to apply varying enchantments of varying amounts * to the generated {@link ItemStack}. * * @param amount The varying amount of enchantments * @param enchantments The collection of enchantment tuples combining the * enchantment and the variable amount of level to apply * @return The new biconsumer to apply to an itemstack builder */ public static BiConsumer<ItemStack.Builder, Random> enchantments(VariableAmount amount, Collection<Tuple<Enchantment, VariableAmount>> enchantments) { checkNotNull(amount, "VariableAmount cannot be null!"); final WeightedTable<Function<Random, ItemEnchantment>> suppliers = new WeightedTable<>(amount); for (Tuple<Enchantment, VariableAmount> enchantment : enchantments) { suppliers.add(random -> new ItemEnchantment(enchantment.getFirst(), enchantment.getSecond().getFlooredAmount(random)), 1); } return listValueSuppliers(Keys.ITEM_ENCHANTMENTS, suppliers); } private ItemStackBuilderPopulators() { } }