From 02d1d95dd54285cc1237d1b5016401274a5ae5f0 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Thu, 25 Mar 2021 18:15:16 +0800 Subject: Refactor Default Plugin packages, fix favorites Signed-off-by: shedaniel --- .../rei/api/client/gui/SimpleDisplayRenderer.java | 14 ++- .../rei/api/client/gui/widgets/WidgetHolder.java | 9 ++ .../rei/api/client/gui/widgets/Widgets.java | 42 ++++++++- .../rei/api/common/entry/EntryIngredient.java | 23 +++++ .../rei/api/common/transfer/info/MenuInfo.java | 2 +- .../info/simple/RecipeBookGridMenuInfo.java | 72 +++++++++++++++ .../me/shedaniel/rei/api/common/util/Animator.java | 102 +++++++++++++++++++++ .../rei/api/common/util/EntryIngredients.java | 28 ++---- .../shedaniel/rei/api/common/util/EntryStacks.java | 91 +++++++----------- .../main/java/me/shedaniel/rei/impl/Internals.java | 4 + 10 files changed, 305 insertions(+), 82 deletions(-) create mode 100644 api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/WidgetHolder.java create mode 100644 api/src/main/java/me/shedaniel/rei/api/common/transfer/info/simple/RecipeBookGridMenuInfo.java create mode 100644 api/src/main/java/me/shedaniel/rei/api/common/util/Animator.java (limited to 'api/src/main/java/me/shedaniel') diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java index 12dec407f..9765edb99 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/SimpleDisplayRenderer.java @@ -30,12 +30,14 @@ import me.shedaniel.math.Point; import me.shedaniel.math.Rectangle; import me.shedaniel.rei.api.client.gui.widgets.Slot; import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.WidgetHolder; import me.shedaniel.rei.api.client.gui.widgets.Widgets; import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.api.common.util.EntryStacks; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import org.jetbrains.annotations.ApiStatus; @@ -46,18 +48,21 @@ import java.util.Comparator; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; -public class SimpleDisplayRenderer extends DisplayRenderer { +public class SimpleDisplayRenderer extends DisplayRenderer implements WidgetHolder { private static final Comparator> ENTRY_COMPARATOR = Comparator.comparingLong(EntryStacks::hashExact); private static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/recipecontainer.png"); private List inputWidgets; private List outputWidgets; + private List widgets; @ApiStatus.Internal private SimpleDisplayRenderer(List input, List output) { this.inputWidgets = simplify(input).stream().filter(stacks -> !stacks.isEmpty()).map(stacks -> Widgets.createSlot(new Point(0, 0)).entries(stacks).disableBackground().disableHighlight().disableTooltips()).collect(Collectors.toList()); this.outputWidgets = CollectionUtils.map(simplify(output), outputStacks -> Widgets.createSlot(new Point(0, 0)).entries(CollectionUtils.filterToList(outputStacks, stack -> !stack.isEmpty())).disableBackground().disableHighlight().disableTooltips()); + this.widgets = Stream.concat(inputWidgets.stream(), outputWidgets.stream()).collect(Collectors.toList()); } private static List simplify(List original) { @@ -149,4 +154,9 @@ public class SimpleDisplayRenderer extends DisplayRenderer { public int getItemsPerLine() { return Mth.floor((getWidth() - 4f) / 18f); } + + @Override + public List children() { + return widgets; + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/WidgetHolder.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/WidgetHolder.java new file mode 100644 index 000000000..74d66a18a --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/WidgetHolder.java @@ -0,0 +1,9 @@ +package me.shedaniel.rei.api.client.gui.widgets; + +import net.minecraft.client.gui.components.events.GuiEventListener; + +import java.util.List; + +public interface WidgetHolder { + List children(); +} diff --git a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java index 643aa7580..fea6292e3 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/gui/widgets/Widgets.java @@ -23,6 +23,7 @@ package me.shedaniel.rei.api.client.gui.widgets; +import com.google.common.collect.AbstractIterator; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; import me.shedaniel.math.Dimension; @@ -44,11 +45,10 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; @Environment(EnvType.CLIENT) @@ -301,4 +301,40 @@ public final class Widgets { public static void produceClickSound() { Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F)); } + + public static Iterable walk(Iterable listeners, Predicate predicate) { + return () -> new AbstractIterator() { + Stack> stack; + + { + stack = new Stack<>(); + stack.push(listeners.iterator()); + } + + @Override + protected T computeNext() { + while (!stack.empty()) { + Iterator peek = stack.peek(); + GuiEventListener listener = peek.next(); + if (!peek.hasNext()) + stack.pop(); + if (predicate.test(listener)) { + return (T) listener; + } + if (listener instanceof ContainerEventHandler) { + List children = ((ContainerEventHandler) listener).children(); + if (!children.isEmpty()) { + stack.push(children.iterator()); + } + } else if (listener instanceof WidgetHolder) { + List children = ((WidgetHolder) listener).children(); + if (!children.isEmpty()) { + stack.push(children.iterator()); + } + } + } + return endOfData(); + } + }; + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java index fde4d8d8b..103586d35 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/entry/EntryIngredient.java @@ -51,6 +51,14 @@ public interface EntryIngredient extends List> { return Internals.getEntryIngredientProvider().of((Iterable>) (Iterable) stacks); } + static Builder builder() { + return Internals.getEntryIngredientProvider().builder(); + } + + static Builder builder(int initialCapacity) { + return Internals.getEntryIngredientProvider().builder(initialCapacity); + } + static EntryIngredient from(ListTag tag) { if (tag.isEmpty()) return empty(); EntryStack[] stacks = new EntryStack[tag.size()]; @@ -61,4 +69,19 @@ public interface EntryIngredient extends List> { } ListTag save(); + + @SuppressWarnings("rawtypes") + default List> cast() { + return (List>) (List) this; + } + + interface Builder { + Builder add(EntryStack stack); + + Builder add(EntryStack... stacks); + + Builder addAll(Iterable> stacks); + + EntryIngredient build(); + } } diff --git a/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/MenuInfo.java b/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/MenuInfo.java index d8b453f43..0a7560a8f 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/MenuInfo.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/MenuInfo.java @@ -49,7 +49,7 @@ import java.util.List; * @see me.shedaniel.rei.api.common.transfer.info.simple.SimpleGridMenuInfo */ public interface MenuInfo { - Class getContainerClass(); + Class getMenuClass(); default RecipeFinderPopulator getRecipeFinderPopulator() { return (context, recipeFinder) -> { diff --git a/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/simple/RecipeBookGridMenuInfo.java b/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/simple/RecipeBookGridMenuInfo.java new file mode 100644 index 000000000..a513c649a --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/common/transfer/info/simple/RecipeBookGridMenuInfo.java @@ -0,0 +1,72 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 shedaniel + * + * 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 me.shedaniel.rei.api.common.transfer.info.simple; + +import me.shedaniel.rei.api.common.display.SimpleMenuDisplay; +import me.shedaniel.rei.api.common.transfer.RecipeFinder; +import net.minecraft.world.inventory.RecipeBookMenu; +import net.minecraft.world.item.ItemStack; + +public class RecipeBookGridMenuInfo, D extends SimpleMenuDisplay> implements SimpleGridMenuInfo { + private final Class> menuClass; + + public RecipeBookGridMenuInfo(Class menuClass) { + this.menuClass = menuClass; + } + + @Override + public Class getMenuClass() { + return (Class) menuClass; + } + + @Override + public int getCraftingResultSlotIndex(T menu) { + return menu.getResultSlotIndex(); + } + + @Override + public int getCraftingWidth(T menu) { + return menu.getGridWidth(); + } + + @Override + public int getCraftingHeight(T menu) { + return menu.getGridHeight(); + } + + @Override + public void clearInputSlots(T menu) { + menu.clearCraftingContent(); + } + + @Override + public void populateRecipeFinder(T container, RecipeFinder finder) { + container.fillCraftSlotsStackedContents(new net.minecraft.world.entity.player.StackedContents() { + @Override + public void accountSimpleStack(ItemStack stack) { + finder.addNormalItem(stack); + } + }); + } +} diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/Animator.java b/api/src/main/java/me/shedaniel/rei/api/common/util/Animator.java new file mode 100644 index 000000000..e0e313c16 --- /dev/null +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/Animator.java @@ -0,0 +1,102 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020 shedaniel + * + * 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 me.shedaniel.rei.api.common.util; + +import me.shedaniel.clothconfig2.impl.EasingMethod; +import net.minecraft.Util; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public final class Animator extends Number { + private double amount; + private double target; + private long start; + private long duration; + + public Animator() { + } + + public Animator(double amount) { + setAs(amount); + } + + public void setAs(double value) { + this.set(value, false, 0); + } + + public void setTo(double value, long duration) { + if (target != value) + this.set(value, true, duration); + } + + private void set(double value, boolean animated, long duration) { + this.target = value; + this.start = Util.getMillis(); + + if (animated) { + this.duration = duration; + } else { + this.duration = 0; + this.amount = this.target; + } + } + + public void update(double delta) { + if (duration != 0) { + if (amount < target) { + this.amount = Math.min(ease(amount, target + (target - amount), Math.min(((double) Util.getMillis() - start) / duration * delta * 3.0D, 1.0D), EasingMethod.EasingMethodImpl.LINEAR), target); + } else if (amount > target) { + this.amount = Math.max(ease(amount, target - (amount - target), Math.min(((double) Util.getMillis() - start) / duration * delta * 3.0D, 1.0D), EasingMethod.EasingMethodImpl.LINEAR), target); + } + } + } + + private static double ease(double start, double end, double amount, EasingMethod easingMethod) { + return start + (end - start) * easingMethod.apply(amount); + } + + @Override + public int intValue() { + return (int) amount; + } + + @Override + public long longValue() { + return (long) amount; + } + + @Override + public float floatValue() { + return (float) amount; + } + + @Override + public double doubleValue() { + return amount; + } + + public double target() { + return target; + } +} diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/EntryIngredients.java b/api/src/main/java/me/shedaniel/rei/api/common/util/EntryIngredients.java index d61f975ad..9b022ff28 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/util/EntryIngredients.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/EntryIngredients.java @@ -30,6 +30,7 @@ import me.shedaniel.rei.api.common.entry.EntryIngredient; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.EntryDefinition; import me.shedaniel.rei.api.common.entry.type.EntryType; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.world.item.ItemStack; @@ -80,35 +81,25 @@ public final class EntryIngredients { public static EntryIngredient of(EntryDefinition definition, Collection values) { if (values.size() == 0) return EntryIngredient.empty(); if (values.size() == 1) return EntryIngredient.of(EntryStack.of(definition, values.iterator().next())); - List> result = new ArrayList<>(values.size()); + EntryIngredient.Builder result = EntryIngredient.builder(values.size()); for (T value : values) { result.add(EntryStack.of(definition, value)); } - return EntryIngredient.of(result); + return result.build(); } public static EntryIngredient ofItems(Collection stacks) { if (stacks.size() == 0) return EntryIngredient.empty(); if (stacks.size() == 1) return EntryIngredient.of(EntryStacks.of(stacks.iterator().next())); - List> result = new ArrayList<>(stacks.size()); + EntryIngredient.Builder result = EntryIngredient.builder(stacks.size()); for (ItemLike stack : stacks) { result.add(EntryStacks.of(stack)); } - return EntryIngredient.of(result); + return result.build(); } public static EntryIngredient ofItemStacks(Collection stacks) { - if (stacks.size() == 0) return EntryIngredient.empty(); - if (stacks.size() == 1) { - ItemStack stack = stacks.iterator().next(); - if (stack.isEmpty()) return EntryIngredient.empty(); - return EntryIngredient.of(EntryStacks.of(stack)); - } - List> result = new ArrayList<>(stacks.size()); - for (ItemStack stack : stacks) { - result.add(EntryStacks.of(stack)); - } - return EntryIngredient.of(result); + return of(VanillaEntryTypes.ITEM, stacks); } public static EntryIngredient ofIngredient(Ingredient ingredient) { @@ -116,12 +107,13 @@ public final class EntryIngredients { ItemStack[] matchingStacks = ingredient.getItems(); if (matchingStacks.length == 0) return EntryIngredient.empty(); if (matchingStacks.length == 1) return EntryIngredient.of(EntryStacks.of(matchingStacks[0])); - List> result = new ArrayList<>(matchingStacks.length); + EntryIngredient.Builder result = EntryIngredient.builder(matchingStacks.length); for (ItemStack matchingStack : matchingStacks) { - if (!matchingStack.isEmpty()) + if (!matchingStack.isEmpty()) { result.add(EntryStacks.of(matchingStack)); + } } - return EntryIngredient.of(result); + return result.build(); } public static List ofIngredients(List ingredients) { diff --git a/api/src/main/java/me/shedaniel/rei/api/common/util/EntryStacks.java b/api/src/main/java/me/shedaniel/rei/api/common/util/EntryStacks.java index b28d91add..b7882298b 100644 --- a/api/src/main/java/me/shedaniel/rei/api/common/util/EntryStacks.java +++ b/api/src/main/java/me/shedaniel/rei/api/common/util/EntryStacks.java @@ -23,7 +23,6 @@ package me.shedaniel.rei.api.common.util; -import com.google.common.collect.ImmutableList; import me.shedaniel.architectury.fluid.FluidStack; import me.shedaniel.architectury.utils.Fraction; import me.shedaniel.rei.api.common.entry.EntryStack; @@ -35,11 +34,10 @@ import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.material.Fluid; -import java.util.*; +import java.util.Iterator; import java.util.stream.Stream; public final class EntryStacks { @@ -73,61 +71,18 @@ public final class EntryStacks { return of(new ItemStack(item)); } - public static List> ofItems(Collection stacks) { - if (stacks.size() == 0) return Collections.emptyList(); - if (stacks.size() == 1) return Collections.singletonList(of(stacks.iterator().next())); - List> result = new ArrayList<>(stacks.size()); - for (ItemLike stack : stacks) { - result.add(of(stack)); - } - return ImmutableList.copyOf(result); - } - - public static List> ofItemStacks(Collection stacks) { - if (stacks.size() == 0) return Collections.emptyList(); - if (stacks.size() == 1) { - ItemStack stack = stacks.iterator().next(); - if (stack.isEmpty()) return Collections.emptyList(); - return Collections.singletonList(of(stack)); - } - List> result = new ArrayList<>(stacks.size()); - for (ItemStack stack : stacks) { - result.add(of(stack)); - } - return ImmutableList.copyOf(result); - } - - public static List> ofIngredient(Ingredient ingredient) { - if (ingredient.isEmpty()) return Collections.emptyList(); - ItemStack[] matchingStacks = ingredient.getItems(); - if (matchingStacks.length == 0) return Collections.emptyList(); - if (matchingStacks.length == 1) return Collections.singletonList(of(matchingStacks[0])); - List> result = new ArrayList<>(matchingStacks.length); - for (ItemStack matchingStack : matchingStacks) { - if (!matchingStack.isEmpty()) - result.add(of(matchingStack)); - } - return ImmutableList.copyOf(result); - } - - public static List>> ofIngredients(List ingredients) { - if (ingredients.size() == 0) return Collections.emptyList(); - if (ingredients.size() == 1) { - Ingredient ingredient = ingredients.get(0); - if (ingredient.isEmpty()) return Collections.emptyList(); - return Collections.singletonList(ofIngredient(ingredient)); - } - boolean emptyFlag = true; - List>> result = new ArrayList<>(ingredients.size()); - for (int i = ingredients.size() - 1; i >= 0; i--) { - Ingredient ingredient = ingredients.get(i); - if (emptyFlag && ingredient.isEmpty()) continue; - result.add(0, ofIngredient(ingredient)); - emptyFlag = false; - } - return ImmutableList.copyOf(result); - } - + /** + * Compares equality under the provided {@code context}. + * Prioritizes {@link me.shedaniel.rei.api.common.entry.type.EntryDefinition#equals(Object, Object, ComparisonContext)} then compares + * with {@link EntryTypeBridge} for differing {@link EntryType}. + *

+ * For example, a lava bucket should still be equals to a lava fluid. + * + * @param left the first stack to compare + * @param right the second stack to compare + * @param context the context of the equality check + * @return the equality under the provided {@code context} + */ public static boolean equals(EntryStack left, EntryStack right, ComparisonContext context) { if (left == null) return right == null; if (right == null) return left == null; @@ -164,10 +119,30 @@ public final class EntryStacks { return false; } + /** + * Compares equality for the {@link ComparisonContext#EXACT} context, stacks that equal should share the same normalized stack. + *

+ * For example, enchantment books of different enchantments will not be equal under this context. + * However, difference between the amount of objects in a stack will not affect the result. + * + * @param left the first stack to compare + * @param right the second stack to compare + * @return the equality for the {@link ComparisonContext#EXACT} context + */ public static boolean equalsExact(EntryStack left, EntryStack right) { return equals(left, right, ComparisonContext.EXACT); } + /** + * Compares equality for the {@link ComparisonContext#FUZZY} context, stacks that equal may not share the same normalized stack. + * This result is less specific, mainly used for fuzzy matching between different stacks. + *

+ * For example, enchantment books of different enchantments should still be equal under this context. + * + * @param left the first stack to compare + * @param right the second stack to compare + * @return the equality for the {@link ComparisonContext#EXACT} context + */ public static boolean equalsFuzzy(EntryStack left, EntryStack right) { return equals(left, right, ComparisonContext.FUZZY); } diff --git a/api/src/main/java/me/shedaniel/rei/impl/Internals.java b/api/src/main/java/me/shedaniel/rei/impl/Internals.java index afa599934..6c2bc189b 100644 --- a/api/src/main/java/me/shedaniel/rei/impl/Internals.java +++ b/api/src/main/java/me/shedaniel/rei/impl/Internals.java @@ -123,6 +123,10 @@ public final class Internals { EntryIngredient of(EntryStack... stacks); EntryIngredient of(Iterable> stacks); + + EntryIngredient.Builder builder(); + + EntryIngredient.Builder builder(int initialCapacity); } public interface NbtHasherProvider { -- cgit