minecraft-src/net/minecraft/world/item/crafting/Ingredient.java
2025-07-04 02:00:41 +03:00

115 lines
4.3 KiB
Java

package net.minecraft.world.item.crafting;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.HolderSetCodec;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.display.SlotDisplay;
import net.minecraft.world.level.ItemLike;
import org.jetbrains.annotations.Nullable;
public final class Ingredient implements Predicate<ItemStack> {
public static final StreamCodec<RegistryFriendlyByteBuf, Ingredient> CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
.map(Ingredient::new, ingredient -> ingredient.values);
public static final StreamCodec<RegistryFriendlyByteBuf, Optional<Ingredient>> OPTIONAL_CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM)
.map(
holderSet -> holderSet.size() == 0 ? Optional.empty() : Optional.of(new Ingredient(holderSet)),
optional -> (HolderSet)optional.map(ingredient -> ingredient.values).orElse(HolderSet.direct())
);
public static final Codec<HolderSet<Item>> NON_AIR_HOLDER_SET_CODEC = HolderSetCodec.create(Registries.ITEM, Item.CODEC, false);
public static final Codec<Ingredient> CODEC = ExtraCodecs.nonEmptyHolderSet(NON_AIR_HOLDER_SET_CODEC).xmap(Ingredient::new, ingredient -> ingredient.values);
private final HolderSet<Item> values;
@Nullable
private List<Holder<Item>> items;
private Ingredient(HolderSet<Item> holderSet) {
holderSet.unwrap().ifRight(list -> {
if (list.isEmpty()) {
throw new UnsupportedOperationException("Ingredients can't be empty");
} else if (list.contains(Items.AIR.builtInRegistryHolder())) {
throw new UnsupportedOperationException("Ingredient can't contain air");
}
});
this.values = holderSet;
}
public static boolean testOptionalIngredient(Optional<Ingredient> optional, ItemStack itemStack) {
return (Boolean)optional.map(ingredient -> ingredient.test(itemStack)).orElseGet(itemStack::isEmpty);
}
public List<Holder<Item>> items() {
if (this.items == null) {
this.items = ImmutableList.copyOf(this.values);
}
return this.items;
}
public boolean test(ItemStack stack) {
List<Holder<Item>> list = this.items();
for (int i = 0; i < list.size(); i++) {
if (stack.is((Holder<Item>)list.get(i))) {
return true;
}
}
return false;
}
public boolean equals(Object object) {
return object instanceof Ingredient ingredient ? Objects.equals(this.values, ingredient.values) : false;
}
public static Ingredient of(ItemLike itemLike) {
return new Ingredient(HolderSet.direct(itemLike.asItem().builtInRegistryHolder()));
}
public static Ingredient of(ItemLike... items) {
return of(Arrays.stream(items));
}
public static Ingredient of(Stream<? extends ItemLike> stacks) {
return new Ingredient(HolderSet.direct(stacks.map(itemLike -> itemLike.asItem().builtInRegistryHolder()).toList()));
}
public static Ingredient of(HolderSet<Item> holderSet) {
return new Ingredient(holderSet);
}
public SlotDisplay display() {
return this.values
.unwrap()
.map(SlotDisplay.TagSlotDisplay::new, list -> new SlotDisplay.Composite(list.stream().map(Ingredient::displayForSingleItem).toList()));
}
public static SlotDisplay optionalIngredientToDisplay(Optional<Ingredient> optional) {
return (SlotDisplay)optional.map(Ingredient::display).orElse(SlotDisplay.Empty.INSTANCE);
}
private static SlotDisplay displayForSingleItem(Holder<Item> holder) {
SlotDisplay slotDisplay = new SlotDisplay.ItemSlotDisplay(holder);
ItemStack itemStack = holder.value().getCraftingRemainder();
if (!itemStack.isEmpty()) {
SlotDisplay slotDisplay2 = new SlotDisplay.ItemStackSlotDisplay(itemStack);
return new SlotDisplay.WithRemainder(slotDisplay, slotDisplay2);
} else {
return slotDisplay;
}
}
}