2025-11-24 22:52:51 +03:00

1095 lines
47 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.google.common.collect.Lists
* com.mojang.datafixers.kinds.App
* com.mojang.datafixers.kinds.Applicative
* com.mojang.logging.LogUtils
* com.mojang.serialization.Codec
* com.mojang.serialization.DataResult
* com.mojang.serialization.DataResult$Error
* com.mojang.serialization.MapCodec
* com.mojang.serialization.codecs.RecordCodecBuilder
* io.netty.handler.codec.DecoderException
* io.netty.handler.codec.EncoderException
* org.apache.commons.lang3.function.TriConsumer
* org.apache.commons.lang3.mutable.MutableBoolean
* org.jspecify.annotations.Nullable
* org.slf4j.Logger
*/
package net.minecraft.world.item;
import com.google.common.collect.Lists;
import com.mojang.datafixers.kinds.App;
import com.mojang.datafixers.kinds.Applicative;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import net.minecraft.ChatFormatting;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.NonNullList;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.core.component.DataComponentHolder;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.component.PatchedDataComponentMap;
import net.minecraft.core.component.TypedDataComponent;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.RegistryOps;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import net.minecraft.tags.TagKey;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.Mth;
import net.minecraft.util.NullOps;
import net.minecraft.util.StringUtil;
import net.minecraft.util.Unit;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.SlotAccess;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.inventory.ClickAction;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.AdventureModePredicate;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemUseAnimation;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.component.Consumable;
import net.minecraft.world.item.component.DamageResistant;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.item.component.KineticWeapon;
import net.minecraft.world.item.component.SwingAnimation;
import net.minecraft.world.item.component.TooltipDisplay;
import net.minecraft.world.item.component.TooltipProvider;
import net.minecraft.world.item.component.TypedEntityData;
import net.minecraft.world.item.component.UseCooldown;
import net.minecraft.world.item.component.UseRemainder;
import net.minecraft.world.item.component.Weapon;
import net.minecraft.world.item.component.WrittenBookContent;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import net.minecraft.world.item.enchantment.Repairable;
import net.minecraft.world.item.equipment.Equippable;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.Spawner;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
import org.apache.commons.lang3.function.TriConsumer;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
public final class ItemStack
implements DataComponentHolder {
private static final List<Component> OP_NBT_WARNING = List.of(Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED), Component.translatable("item.op_warning.line3").withStyle(ChatFormatting.RED));
private static final Component UNBREAKABLE_TOOLTIP = Component.translatable("item.unbreakable").withStyle(ChatFormatting.BLUE);
private static final Component INTANGIBLE_TOOLTIP = Component.translatable("item.intangible").withStyle(ChatFormatting.GRAY);
public static final MapCodec<ItemStack> MAP_CODEC = MapCodec.recursive((String)"ItemStack", subCodec -> RecordCodecBuilder.mapCodec(i -> i.group((App)Item.CODEC.fieldOf("id").forGetter(ItemStack::getItemHolder), (App)ExtraCodecs.intRange(1, 99).fieldOf("count").orElse((Object)1).forGetter(ItemStack::getCount), (App)DataComponentPatch.CODEC.optionalFieldOf("components", (Object)DataComponentPatch.EMPTY).forGetter(s -> s.components.asPatch())).apply((Applicative)i, ItemStack::new)));
public static final Codec<ItemStack> CODEC = Codec.lazyInitialized(() -> MAP_CODEC.codec());
public static final Codec<ItemStack> SINGLE_ITEM_CODEC = Codec.lazyInitialized(() -> RecordCodecBuilder.create(i -> i.group((App)Item.CODEC.fieldOf("id").forGetter(ItemStack::getItemHolder), (App)DataComponentPatch.CODEC.optionalFieldOf("components", (Object)DataComponentPatch.EMPTY).forGetter(s -> s.components.asPatch())).apply((Applicative)i, (item, components) -> new ItemStack((Holder<Item>)item, 1, (DataComponentPatch)components))));
public static final Codec<ItemStack> STRICT_CODEC = CODEC.validate(ItemStack::validateStrict);
public static final Codec<ItemStack> STRICT_SINGLE_ITEM_CODEC = SINGLE_ITEM_CODEC.validate(ItemStack::validateStrict);
public static final Codec<ItemStack> OPTIONAL_CODEC = ExtraCodecs.optionalEmptyMap(CODEC).xmap(itemStack -> itemStack.orElse(EMPTY), itemStack -> itemStack.isEmpty() ? Optional.empty() : Optional.of(itemStack));
public static final Codec<ItemStack> SIMPLE_ITEM_CODEC = Item.CODEC.xmap(ItemStack::new, ItemStack::getItemHolder);
public static final StreamCodec<RegistryFriendlyByteBuf, ItemStack> OPTIONAL_STREAM_CODEC = ItemStack.createOptionalStreamCodec(DataComponentPatch.STREAM_CODEC);
public static final StreamCodec<RegistryFriendlyByteBuf, ItemStack> OPTIONAL_UNTRUSTED_STREAM_CODEC = ItemStack.createOptionalStreamCodec(DataComponentPatch.DELIMITED_STREAM_CODEC);
public static final StreamCodec<RegistryFriendlyByteBuf, ItemStack> STREAM_CODEC = new StreamCodec<RegistryFriendlyByteBuf, ItemStack>(){
@Override
public ItemStack decode(RegistryFriendlyByteBuf input) {
ItemStack itemStack = (ItemStack)OPTIONAL_STREAM_CODEC.decode(input);
if (itemStack.isEmpty()) {
throw new DecoderException("Empty ItemStack not allowed");
}
return itemStack;
}
@Override
public void encode(RegistryFriendlyByteBuf output, ItemStack itemStack) {
if (itemStack.isEmpty()) {
throw new EncoderException("Empty ItemStack not allowed");
}
OPTIONAL_STREAM_CODEC.encode(output, itemStack);
}
};
public static final StreamCodec<RegistryFriendlyByteBuf, List<ItemStack>> OPTIONAL_LIST_STREAM_CODEC = OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs.collection(NonNullList::createWithCapacity));
private static final Logger LOGGER = LogUtils.getLogger();
public static final ItemStack EMPTY = new ItemStack((Void)null);
private static final Component DISABLED_ITEM_TOOLTIP = Component.translatable("item.disabled").withStyle(ChatFormatting.RED);
private int count;
private int popTime;
@Deprecated
private final @Nullable Item item;
private final PatchedDataComponentMap components;
private @Nullable Entity entityRepresentation;
public static DataResult<ItemStack> validateStrict(ItemStack itemStack) {
DataResult<Unit> result = ItemStack.validateComponents(itemStack.getComponents());
if (result.isError()) {
return result.map(unit -> itemStack);
}
if (itemStack.getCount() > itemStack.getMaxStackSize()) {
return DataResult.error(() -> "Item stack with stack size of " + itemStack.getCount() + " was larger than maximum: " + itemStack.getMaxStackSize());
}
return DataResult.success((Object)itemStack);
}
private static StreamCodec<RegistryFriendlyByteBuf, ItemStack> createOptionalStreamCodec(final StreamCodec<RegistryFriendlyByteBuf, DataComponentPatch> patchCodec) {
return new StreamCodec<RegistryFriendlyByteBuf, ItemStack>(){
@Override
public ItemStack decode(RegistryFriendlyByteBuf input) {
int count = input.readVarInt();
if (count <= 0) {
return EMPTY;
}
Holder item = (Holder)Item.STREAM_CODEC.decode(input);
DataComponentPatch patch = (DataComponentPatch)patchCodec.decode(input);
return new ItemStack(item, count, patch);
}
@Override
public void encode(RegistryFriendlyByteBuf output, ItemStack itemStack) {
if (itemStack.isEmpty()) {
output.writeVarInt(0);
return;
}
output.writeVarInt(itemStack.getCount());
Item.STREAM_CODEC.encode(output, itemStack.getItemHolder());
patchCodec.encode(output, itemStack.components.asPatch());
}
};
}
public static StreamCodec<RegistryFriendlyByteBuf, ItemStack> validatedStreamCodec(final StreamCodec<RegistryFriendlyByteBuf, ItemStack> codec) {
return new StreamCodec<RegistryFriendlyByteBuf, ItemStack>(){
@Override
public ItemStack decode(RegistryFriendlyByteBuf input) {
ItemStack itemStack = (ItemStack)codec.decode(input);
if (!itemStack.isEmpty()) {
RegistryOps<Unit> ops = input.registryAccess().createSerializationContext(NullOps.INSTANCE);
CODEC.encodeStart(ops, (Object)itemStack).getOrThrow(DecoderException::new);
}
return itemStack;
}
@Override
public void encode(RegistryFriendlyByteBuf output, ItemStack value) {
codec.encode(output, value);
}
};
}
public Optional<TooltipComponent> getTooltipImage() {
return this.getItem().getTooltipImage(this);
}
@Override
public DataComponentMap getComponents() {
return !this.isEmpty() ? this.components : DataComponentMap.EMPTY;
}
public DataComponentMap getPrototype() {
return !this.isEmpty() ? this.getItem().components() : DataComponentMap.EMPTY;
}
public DataComponentPatch getComponentsPatch() {
return !this.isEmpty() ? this.components.asPatch() : DataComponentPatch.EMPTY;
}
public DataComponentMap immutableComponents() {
return !this.isEmpty() ? this.components.toImmutableMap() : DataComponentMap.EMPTY;
}
public boolean hasNonDefault(DataComponentType<?> type) {
return !this.isEmpty() && this.components.hasNonDefault(type);
}
public ItemStack(ItemLike item) {
this(item, 1);
}
public ItemStack(Holder<Item> item) {
this(item.value(), 1);
}
public ItemStack(Holder<Item> item, int count, DataComponentPatch components) {
this(item.value(), count, PatchedDataComponentMap.fromPatch(item.value().components(), components));
}
public ItemStack(Holder<Item> item, int count) {
this(item.value(), count);
}
public ItemStack(ItemLike item, int count) {
this(item, count, new PatchedDataComponentMap(item.asItem().components()));
}
private ItemStack(ItemLike item, int count, PatchedDataComponentMap components) {
this.item = item.asItem();
this.count = count;
this.components = components;
}
private ItemStack(@Nullable Void nullMarker) {
this.item = null;
this.components = new PatchedDataComponentMap(DataComponentMap.EMPTY);
}
public static DataResult<Unit> validateComponents(DataComponentMap components) {
if (components.has(DataComponents.MAX_DAMAGE) && components.getOrDefault(DataComponents.MAX_STACK_SIZE, 1) > 1) {
return DataResult.error(() -> "Item cannot be both damageable and stackable");
}
ItemContainerContents container = components.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
for (ItemStack item : container.nonEmptyItems()) {
int maxStackSize;
int itemCount = item.getCount();
if (itemCount <= (maxStackSize = item.getMaxStackSize())) continue;
return DataResult.error(() -> "Item stack with count of " + itemCount + " was larger than maximum: " + maxStackSize);
}
return DataResult.success((Object)((Object)Unit.INSTANCE));
}
public boolean isEmpty() {
return this == EMPTY || this.item == Items.AIR || this.count <= 0;
}
public boolean isItemEnabled(FeatureFlagSet enabledFeatures) {
return this.isEmpty() || this.getItem().isEnabled(enabledFeatures);
}
public ItemStack split(int amount) {
int realAmount = Math.min(amount, this.getCount());
ItemStack result = this.copyWithCount(realAmount);
this.shrink(realAmount);
return result;
}
public ItemStack copyAndClear() {
if (this.isEmpty()) {
return EMPTY;
}
ItemStack result = this.copy();
this.setCount(0);
return result;
}
public Item getItem() {
return this.isEmpty() ? Items.AIR : this.item;
}
public Holder<Item> getItemHolder() {
return this.getItem().builtInRegistryHolder();
}
public boolean is(TagKey<Item> tag) {
return this.getItem().builtInRegistryHolder().is(tag);
}
public boolean is(Item item) {
return this.getItem() == item;
}
public boolean is(Predicate<Holder<Item>> item) {
return item.test(this.getItem().builtInRegistryHolder());
}
public boolean is(Holder<Item> item) {
return this.getItem().builtInRegistryHolder() == item;
}
public boolean is(HolderSet<Item> set) {
return set.contains(this.getItemHolder());
}
public Stream<TagKey<Item>> getTags() {
return this.getItem().builtInRegistryHolder().tags();
}
public InteractionResult useOn(UseOnContext context) {
InteractionResult.Success success;
Player player = context.getPlayer();
BlockPos pos = context.getClickedPos();
if (player != null && !player.getAbilities().mayBuild && !this.canPlaceOnBlockInAdventureMode(new BlockInWorld(context.getLevel(), pos, false))) {
return InteractionResult.PASS;
}
Item usedItem = this.getItem();
InteractionResult result = usedItem.useOn(context);
if (player != null && result instanceof InteractionResult.Success && (success = (InteractionResult.Success)result).wasItemInteraction()) {
player.awardStat(Stats.ITEM_USED.get(usedItem));
}
return result;
}
public float getDestroySpeed(BlockState state) {
return this.getItem().getDestroySpeed(this, state);
}
public InteractionResult use(Level level, Player player, InteractionHand hand) {
ItemStack stackBeforeUse = this.copy();
boolean isInstantlyUsed = this.getUseDuration(player) <= 0;
InteractionResult result = this.getItem().use(level, player, hand);
if (isInstantlyUsed && result instanceof InteractionResult.Success) {
InteractionResult.Success success;
return success.heldItemTransformedTo((success = (InteractionResult.Success)result).heldItemTransformedTo() == null ? this.applyAfterUseComponentSideEffects(player, stackBeforeUse) : success.heldItemTransformedTo().applyAfterUseComponentSideEffects(player, stackBeforeUse));
}
return result;
}
public ItemStack finishUsingItem(Level level, LivingEntity livingEntity) {
ItemStack stackBeforeUse = this.copy();
ItemStack result = this.getItem().finishUsingItem(this, level, livingEntity);
return result.applyAfterUseComponentSideEffects(livingEntity, stackBeforeUse);
}
private ItemStack applyAfterUseComponentSideEffects(LivingEntity user, ItemStack stackBeforeUsing) {
UseRemainder useRemainder = stackBeforeUsing.get(DataComponents.USE_REMAINDER);
UseCooldown useCooldown = stackBeforeUsing.get(DataComponents.USE_COOLDOWN);
int stackCountBeforeUsing = stackBeforeUsing.getCount();
ItemStack result = this;
if (useRemainder != null) {
result = useRemainder.convertIntoRemainder(result, stackCountBeforeUsing, user.hasInfiniteMaterials(), user::handleExtraItemsCreatedOnUse);
}
if (useCooldown != null) {
useCooldown.apply(stackBeforeUsing, user);
}
return result;
}
public int getMaxStackSize() {
return this.getOrDefault(DataComponents.MAX_STACK_SIZE, 1);
}
public boolean isStackable() {
return this.getMaxStackSize() > 1 && (!this.isDamageableItem() || !this.isDamaged());
}
public boolean isDamageableItem() {
return this.has(DataComponents.MAX_DAMAGE) && !this.has(DataComponents.UNBREAKABLE) && this.has(DataComponents.DAMAGE);
}
public boolean isDamaged() {
return this.isDamageableItem() && this.getDamageValue() > 0;
}
public int getDamageValue() {
return Mth.clamp(this.getOrDefault(DataComponents.DAMAGE, 0), 0, this.getMaxDamage());
}
public void setDamageValue(int value) {
this.set(DataComponents.DAMAGE, Mth.clamp(value, 0, this.getMaxDamage()));
}
public int getMaxDamage() {
return this.getOrDefault(DataComponents.MAX_DAMAGE, 0);
}
public boolean isBroken() {
return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage();
}
public boolean nextDamageWillBreak() {
return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1;
}
public void hurtAndBreak(int amount, ServerLevel level, @Nullable ServerPlayer player, Consumer<Item> onBreak) {
int newAmount = this.processDurabilityChange(amount, level, player);
if (newAmount != 0) {
this.applyDamage(this.getDamageValue() + newAmount, player, onBreak);
}
}
private int processDurabilityChange(int amount, ServerLevel level, @Nullable ServerPlayer player) {
if (!this.isDamageableItem()) {
return 0;
}
if (player != null && player.hasInfiniteMaterials()) {
return 0;
}
if (amount > 0) {
return EnchantmentHelper.processDurabilityChange(level, this, amount);
}
return amount;
}
private void applyDamage(int newDamage, @Nullable ServerPlayer player, Consumer<Item> onBreak) {
if (player != null) {
CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(player, this, newDamage);
}
this.setDamageValue(newDamage);
if (this.isBroken()) {
Item item = this.getItem();
this.shrink(1);
onBreak.accept(item);
}
}
public void hurtWithoutBreaking(int amount, Player player) {
if (player instanceof ServerPlayer) {
ServerPlayer serverPlayer = (ServerPlayer)player;
int newAmount = this.processDurabilityChange(amount, serverPlayer.level(), serverPlayer);
if (newAmount == 0) {
return;
}
int newDamage = Math.min(this.getDamageValue() + newAmount, this.getMaxDamage() - 1);
this.applyDamage(newDamage, serverPlayer, i -> {});
}
}
public void hurtAndBreak(int amount, LivingEntity owner, InteractionHand hand) {
this.hurtAndBreak(amount, owner, hand.asEquipmentSlot());
}
public void hurtAndBreak(int amount, LivingEntity owner, EquipmentSlot slot) {
Level level = owner.level();
if (level instanceof ServerLevel) {
ServerPlayer player;
ServerLevel serverLevel = (ServerLevel)level;
this.hurtAndBreak(amount, serverLevel, owner instanceof ServerPlayer ? (player = (ServerPlayer)owner) : null, brokenItem -> owner.onEquippedItemBroken((Item)brokenItem, slot));
}
}
public ItemStack hurtAndConvertOnBreak(int amount, ItemLike newItem, LivingEntity owner, EquipmentSlot slot) {
this.hurtAndBreak(amount, owner, slot);
if (this.isEmpty()) {
ItemStack replacement = this.transmuteCopyIgnoreEmpty(newItem, 1);
if (replacement.isDamageableItem()) {
replacement.setDamageValue(0);
}
return replacement;
}
return this;
}
public boolean isBarVisible() {
return this.getItem().isBarVisible(this);
}
public int getBarWidth() {
return this.getItem().getBarWidth(this);
}
public int getBarColor() {
return this.getItem().getBarColor(this);
}
public boolean overrideStackedOnOther(Slot slot, ClickAction clickAction, Player player) {
return this.getItem().overrideStackedOnOther(this, slot, clickAction, player);
}
public boolean overrideOtherStackedOnMe(ItemStack other, Slot slot, ClickAction clickAction, Player player, SlotAccess carriedItem) {
return this.getItem().overrideOtherStackedOnMe(this, other, slot, clickAction, player, carriedItem);
}
public boolean hurtEnemy(LivingEntity mob, LivingEntity attacker) {
Item usedItem = this.getItem();
usedItem.hurtEnemy(this, mob, attacker);
if (this.has(DataComponents.WEAPON)) {
if (attacker instanceof Player) {
Player player = (Player)attacker;
player.awardStat(Stats.ITEM_USED.get(usedItem));
}
return true;
}
return false;
}
public void postHurtEnemy(LivingEntity mob, LivingEntity attacker) {
this.getItem().postHurtEnemy(this, mob, attacker);
Weapon weapon = this.get(DataComponents.WEAPON);
if (weapon != null) {
this.hurtAndBreak(weapon.itemDamagePerAttack(), attacker, EquipmentSlot.MAINHAND);
}
}
public void mineBlock(Level level, BlockState state, BlockPos pos, Player owner) {
Item usedItem = this.getItem();
if (usedItem.mineBlock(this, level, state, pos, owner)) {
owner.awardStat(Stats.ITEM_USED.get(usedItem));
}
}
public boolean isCorrectToolForDrops(BlockState state) {
return this.getItem().isCorrectToolForDrops(this, state);
}
public InteractionResult interactLivingEntity(Player player, LivingEntity target, InteractionHand hand) {
InteractionResult result;
Equippable equippable = this.get(DataComponents.EQUIPPABLE);
if (equippable != null && equippable.equipOnInteract() && (result = equippable.equipOnTarget(player, target, this)) != InteractionResult.PASS) {
return result;
}
return this.getItem().interactLivingEntity(this, player, target, hand);
}
public ItemStack copy() {
if (this.isEmpty()) {
return EMPTY;
}
ItemStack copy = new ItemStack(this.getItem(), this.count, this.components.copy());
copy.setPopTime(this.getPopTime());
return copy;
}
public ItemStack copyWithCount(int count) {
if (this.isEmpty()) {
return EMPTY;
}
ItemStack copy = this.copy();
copy.setCount(count);
return copy;
}
public ItemStack transmuteCopy(ItemLike newItem) {
return this.transmuteCopy(newItem, this.getCount());
}
public ItemStack transmuteCopy(ItemLike newItem, int newCount) {
if (this.isEmpty()) {
return EMPTY;
}
return this.transmuteCopyIgnoreEmpty(newItem, newCount);
}
private ItemStack transmuteCopyIgnoreEmpty(ItemLike newItem, int newCount) {
return new ItemStack(newItem.asItem().builtInRegistryHolder(), newCount, this.components.asPatch());
}
public static boolean matches(ItemStack a, ItemStack b) {
if (a == b) {
return true;
}
if (a.getCount() != b.getCount()) {
return false;
}
return ItemStack.isSameItemSameComponents(a, b);
}
@Deprecated
public static boolean listMatches(List<ItemStack> left, List<ItemStack> right) {
if (left.size() != right.size()) {
return false;
}
for (int i = 0; i < left.size(); ++i) {
if (ItemStack.matches(left.get(i), right.get(i))) continue;
return false;
}
return true;
}
public static boolean isSameItem(ItemStack a, ItemStack b) {
return a.is(b.getItem());
}
public static boolean isSameItemSameComponents(ItemStack a, ItemStack b) {
if (!a.is(b.getItem())) {
return false;
}
if (a.isEmpty() && b.isEmpty()) {
return true;
}
return Objects.equals(a.components, b.components);
}
public static boolean matchesIgnoringComponents(ItemStack a, ItemStack b, Predicate<DataComponentType<?>> ignoredPredicate) {
if (a == b) {
return true;
}
if (a.getCount() != b.getCount()) {
return false;
}
if (!a.is(b.getItem())) {
return false;
}
if (a.isEmpty() && b.isEmpty()) {
return true;
}
if (a.components.size() != b.components.size()) {
return false;
}
for (DataComponentType<?> type : a.components.keySet()) {
Object componentA = a.components.get(type);
Object componentB = b.components.get(type);
if (componentA == null || componentB == null) {
return false;
}
if (Objects.equals(componentA, componentB) || ignoredPredicate.test(type)) continue;
return false;
}
return true;
}
public static MapCodec<ItemStack> lenientOptionalFieldOf(String name) {
return CODEC.lenientOptionalFieldOf(name).xmap(itemStack -> itemStack.orElse(EMPTY), itemStack -> itemStack.isEmpty() ? Optional.empty() : Optional.of(itemStack));
}
public static int hashItemAndComponents(@Nullable ItemStack item) {
if (item != null) {
int result = 31 + item.getItem().hashCode();
return 31 * result + item.getComponents().hashCode();
}
return 0;
}
@Deprecated
public static int hashStackList(List<ItemStack> items) {
int result = 0;
for (ItemStack item : items) {
result = result * 31 + ItemStack.hashItemAndComponents(item);
}
return result;
}
public String toString() {
return this.getCount() + " " + String.valueOf(this.getItem());
}
public void inventoryTick(Level level, Entity owner, @Nullable EquipmentSlot slot) {
if (this.popTime > 0) {
--this.popTime;
}
if (level instanceof ServerLevel) {
ServerLevel serverLevel = (ServerLevel)level;
this.getItem().inventoryTick(this, serverLevel, owner, slot);
}
}
public void onCraftedBy(Player player, int craftCount) {
player.awardStat(Stats.ITEM_CRAFTED.get(this.getItem()), craftCount);
this.getItem().onCraftedBy(this, player);
}
public void onCraftedBySystem(Level level) {
this.getItem().onCraftedPostProcess(this, level);
}
public int getUseDuration(LivingEntity user) {
return this.getItem().getUseDuration(this, user);
}
public ItemUseAnimation getUseAnimation() {
return this.getItem().getUseAnimation(this);
}
public void releaseUsing(Level level, LivingEntity entity, int remainingTime) {
ItemStack withSideEffects;
ItemStack stackBeforeUsing = this.copy();
if (this.getItem().releaseUsing(this, level, entity, remainingTime) && (withSideEffects = this.applyAfterUseComponentSideEffects(entity, stackBeforeUsing)) != this) {
entity.setItemInHand(entity.getUsedItemHand(), withSideEffects);
}
}
public boolean useOnRelease() {
return this.getItem().useOnRelease(this);
}
public <T> @Nullable T set(DataComponentType<T> type, @Nullable T value) {
return this.components.set(type, value);
}
public <T> @Nullable T set(TypedDataComponent<T> value) {
return this.components.set(value);
}
public <T> void copyFrom(DataComponentType<T> type, DataComponentGetter source) {
this.set(type, source.get(type));
}
public <T, U> @Nullable T update(DataComponentType<T> type, T defaultValue, U value, BiFunction<T, U, T> combiner) {
return this.set(type, combiner.apply(this.getOrDefault(type, defaultValue), value));
}
public <T> @Nullable T update(DataComponentType<T> type, T defaultValue, UnaryOperator<T> function) {
T value = this.getOrDefault(type, defaultValue);
return this.set(type, function.apply(value));
}
public <T> @Nullable T remove(DataComponentType<? extends T> type) {
return this.components.remove(type);
}
public void applyComponentsAndValidate(DataComponentPatch patch) {
DataComponentPatch oldPatch = this.components.asPatch();
this.components.applyPatch(patch);
Optional validationError = ItemStack.validateStrict(this).error();
if (validationError.isPresent()) {
LOGGER.error("Failed to apply component patch '{}' to item: '{}'", (Object)patch, (Object)((DataResult.Error)validationError.get()).message());
this.components.restorePatch(oldPatch);
}
}
public void applyComponents(DataComponentPatch patch) {
this.components.applyPatch(patch);
}
public void applyComponents(DataComponentMap components) {
this.components.setAll(components);
}
public Component getHoverName() {
Component customName = this.getCustomName();
if (customName != null) {
return customName;
}
return this.getItemName();
}
public @Nullable Component getCustomName() {
String title;
Component customName = this.get(DataComponents.CUSTOM_NAME);
if (customName != null) {
return customName;
}
WrittenBookContent content = this.get(DataComponents.WRITTEN_BOOK_CONTENT);
if (content != null && !StringUtil.isBlank(title = content.title().raw())) {
return Component.literal(title);
}
return null;
}
public Component getItemName() {
return this.getItem().getName(this);
}
public Component getStyledHoverName() {
MutableComponent hoverName = Component.empty().append(this.getHoverName()).withStyle(this.getRarity().color());
if (this.has(DataComponents.CUSTOM_NAME)) {
hoverName.withStyle(ChatFormatting.ITALIC);
}
return hoverName;
}
public <T extends TooltipProvider> void addToTooltip(DataComponentType<T> type, Item.TooltipContext context, TooltipDisplay display, Consumer<Component> consumer, TooltipFlag flag) {
TooltipProvider component = (TooltipProvider)this.get(type);
if (component != null && display.shows(type)) {
component.addToTooltip(context, consumer, flag, this.components);
}
}
public List<Component> getTooltipLines(Item.TooltipContext context, @Nullable Player player, TooltipFlag tooltipFlag) {
TooltipDisplay display = this.getOrDefault(DataComponents.TOOLTIP_DISPLAY, TooltipDisplay.DEFAULT);
if (!tooltipFlag.isCreative() && display.hideTooltip()) {
boolean shouldPrintOpWarning = this.getItem().shouldPrintOpWarning(this, player);
return shouldPrintOpWarning ? OP_NBT_WARNING : List.of();
}
ArrayList lines = Lists.newArrayList();
lines.add(this.getStyledHoverName());
this.addDetailsToTooltip(context, display, player, tooltipFlag, lines::add);
return lines;
}
public void addDetailsToTooltip(Item.TooltipContext context, TooltipDisplay display, @Nullable Player player, TooltipFlag tooltipFlag, Consumer<Component> builder) {
boolean shouldPrintOpWarning;
AdventureModePredicate canPlaceOn;
AdventureModePredicate canBreak;
this.getItem().appendHoverText(this, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.TROPICAL_FISH_PATTERN, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.INSTRUMENT, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.MAP_ID, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.BEES, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.CONTAINER_LOOT, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.CONTAINER, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.BANNER_PATTERNS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.POT_DECORATIONS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.WRITTEN_BOOK_CONTENT, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.CHARGED_PROJECTILES, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.FIREWORKS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.FIREWORK_EXPLOSION, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.POTION_CONTENTS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.JUKEBOX_PLAYABLE, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.TRIM, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.STORED_ENCHANTMENTS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.ENCHANTMENTS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.DYED_COLOR, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.PROFILE, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.LORE, context, display, builder, tooltipFlag);
this.addAttributeTooltips(builder, display, player);
this.addUnitComponentToTooltip(DataComponents.INTANGIBLE_PROJECTILE, INTANGIBLE_TOOLTIP, display, builder);
this.addUnitComponentToTooltip(DataComponents.UNBREAKABLE, UNBREAKABLE_TOOLTIP, display, builder);
this.addToTooltip(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.SUSPICIOUS_STEW_EFFECTS, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.BLOCK_STATE, context, display, builder, tooltipFlag);
this.addToTooltip(DataComponents.ENTITY_DATA, context, display, builder, tooltipFlag);
if ((this.is(Items.SPAWNER) || this.is(Items.TRIAL_SPAWNER)) && display.shows(DataComponents.BLOCK_ENTITY_DATA)) {
TypedEntityData<BlockEntityType<?>> blockEntityData = this.get(DataComponents.BLOCK_ENTITY_DATA);
Spawner.appendHoverText(blockEntityData, builder, "SpawnData");
}
if ((canBreak = this.get(DataComponents.CAN_BREAK)) != null && display.shows(DataComponents.CAN_BREAK)) {
builder.accept(CommonComponents.EMPTY);
builder.accept(AdventureModePredicate.CAN_BREAK_HEADER);
canBreak.addToTooltip(builder);
}
if ((canPlaceOn = this.get(DataComponents.CAN_PLACE_ON)) != null && display.shows(DataComponents.CAN_PLACE_ON)) {
builder.accept(CommonComponents.EMPTY);
builder.accept(AdventureModePredicate.CAN_PLACE_HEADER);
canPlaceOn.addToTooltip(builder);
}
if (tooltipFlag.isAdvanced()) {
if (this.isDamaged() && display.shows(DataComponents.DAMAGE)) {
builder.accept(Component.translatable("item.durability", this.getMaxDamage() - this.getDamageValue(), this.getMaxDamage()));
}
builder.accept(Component.literal(BuiltInRegistries.ITEM.getKey(this.getItem()).toString()).withStyle(ChatFormatting.DARK_GRAY));
int count = this.components.size();
if (count > 0) {
builder.accept(Component.translatable("item.components", count).withStyle(ChatFormatting.DARK_GRAY));
}
}
if (player != null && !this.getItem().isEnabled(player.level().enabledFeatures())) {
builder.accept(DISABLED_ITEM_TOOLTIP);
}
if (shouldPrintOpWarning = this.getItem().shouldPrintOpWarning(this, player)) {
OP_NBT_WARNING.forEach(builder);
}
}
private void addUnitComponentToTooltip(DataComponentType<?> dataComponentType, Component component, TooltipDisplay display, Consumer<Component> builder) {
if (this.has(dataComponentType) && display.shows(dataComponentType)) {
builder.accept(component);
}
}
private void addAttributeTooltips(Consumer<Component> consumer, TooltipDisplay display, @Nullable Player player) {
if (!display.shows(DataComponents.ATTRIBUTE_MODIFIERS)) {
return;
}
for (EquipmentSlotGroup slot : EquipmentSlotGroup.values()) {
MutableBoolean first = new MutableBoolean(true);
this.forEachModifier(slot, (TriConsumer<Holder<Attribute>, AttributeModifier, ItemAttributeModifiers.Display>)((TriConsumer)(attribute, modifier, tooltip) -> {
if (tooltip == ItemAttributeModifiers.Display.hidden()) {
return;
}
if (first.isTrue()) {
consumer.accept(CommonComponents.EMPTY);
consumer.accept(Component.translatable("item.modifiers." + slot.getSerializedName()).withStyle(ChatFormatting.GRAY));
first.setFalse();
}
tooltip.apply(consumer, player, (Holder<Attribute>)attribute, (AttributeModifier)modifier);
}));
}
}
public boolean hasFoil() {
Boolean enchantmentGlintOverride = this.get(DataComponents.ENCHANTMENT_GLINT_OVERRIDE);
if (enchantmentGlintOverride != null) {
return enchantmentGlintOverride;
}
return this.getItem().isFoil(this);
}
public Rarity getRarity() {
Rarity baseRarity = this.getOrDefault(DataComponents.RARITY, Rarity.COMMON);
if (!this.isEnchanted()) {
return baseRarity;
}
return switch (baseRarity) {
case Rarity.COMMON, Rarity.UNCOMMON -> Rarity.RARE;
case Rarity.RARE -> Rarity.EPIC;
default -> baseRarity;
};
}
public boolean isEnchantable() {
if (!this.has(DataComponents.ENCHANTABLE)) {
return false;
}
ItemEnchantments enchantments = this.get(DataComponents.ENCHANTMENTS);
return enchantments != null && enchantments.isEmpty();
}
public void enchant(Holder<Enchantment> enchantment, int level) {
EnchantmentHelper.updateEnchantments(this, enchantments -> enchantments.upgrade(enchantment, level));
}
public boolean isEnchanted() {
return !this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).isEmpty();
}
public ItemEnchantments getEnchantments() {
return this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
}
public boolean isFramed() {
return this.entityRepresentation instanceof ItemFrame;
}
public void setEntityRepresentation(@Nullable Entity entity) {
if (!this.isEmpty()) {
this.entityRepresentation = entity;
}
}
public @Nullable ItemFrame getFrame() {
return this.entityRepresentation instanceof ItemFrame ? (ItemFrame)this.getEntityRepresentation() : null;
}
public @Nullable Entity getEntityRepresentation() {
return !this.isEmpty() ? this.entityRepresentation : null;
}
public void forEachModifier(EquipmentSlotGroup slot, TriConsumer<Holder<Attribute>, AttributeModifier, ItemAttributeModifiers.Display> consumer) {
ItemAttributeModifiers modifiers = this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY);
modifiers.forEach(slot, consumer);
EnchantmentHelper.forEachModifier(this, slot, (a, b) -> consumer.accept(a, b, (Object)ItemAttributeModifiers.Display.attributeModifiers()));
}
public void forEachModifier(EquipmentSlot slot, BiConsumer<Holder<Attribute>, AttributeModifier> consumer) {
ItemAttributeModifiers modifiers = this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY);
modifiers.forEach(slot, consumer);
EnchantmentHelper.forEachModifier(this, slot, consumer);
}
public Component getDisplayName() {
MutableComponent hoverName = Component.empty().append(this.getHoverName());
if (this.has(DataComponents.CUSTOM_NAME)) {
hoverName.withStyle(ChatFormatting.ITALIC);
}
MutableComponent result = ComponentUtils.wrapInSquareBrackets(hoverName);
if (!this.isEmpty()) {
result.withStyle(this.getRarity().color()).withStyle(s -> s.withHoverEvent(new HoverEvent.ShowItem(this)));
}
return result;
}
public SwingAnimation getSwingAnimation() {
return this.getOrDefault(DataComponents.SWING_ANIMATION, SwingAnimation.DEFAULT);
}
public boolean canPlaceOnBlockInAdventureMode(BlockInWorld blockInWorld) {
AdventureModePredicate canPlaceOn = this.get(DataComponents.CAN_PLACE_ON);
return canPlaceOn != null && canPlaceOn.test(blockInWorld);
}
public boolean canBreakBlockInAdventureMode(BlockInWorld blockInWorld) {
AdventureModePredicate canBreak = this.get(DataComponents.CAN_BREAK);
return canBreak != null && canBreak.test(blockInWorld);
}
public int getPopTime() {
return this.popTime;
}
public void setPopTime(int popTime) {
this.popTime = popTime;
}
public int getCount() {
return this.isEmpty() ? 0 : this.count;
}
public void setCount(int count) {
this.count = count;
}
public void limitSize(int maxStackSize) {
if (!this.isEmpty() && this.getCount() > maxStackSize) {
this.setCount(maxStackSize);
}
}
public void grow(int amount) {
this.setCount(this.getCount() + amount);
}
public void shrink(int amount) {
this.grow(-amount);
}
public void consume(int amount, @Nullable LivingEntity owner) {
if (owner == null || !owner.hasInfiniteMaterials()) {
this.shrink(amount);
}
}
public ItemStack consumeAndReturn(int amount, @Nullable LivingEntity owner) {
ItemStack split = this.copyWithCount(amount);
this.consume(amount, owner);
return split;
}
public void onUseTick(Level level, LivingEntity livingEntity, int ticksRemaining) {
KineticWeapon kineticWeapon;
Consumable consumable = this.get(DataComponents.CONSUMABLE);
if (consumable != null && consumable.shouldEmitParticlesAndSounds(ticksRemaining)) {
consumable.emitParticlesAndSounds(livingEntity.getRandom(), livingEntity, this, 5);
}
if ((kineticWeapon = this.get(DataComponents.KINETIC_WEAPON)) != null && !level.isClientSide()) {
kineticWeapon.damageEntities(this, ticksRemaining, livingEntity, livingEntity.getUsedItemHand().asEquipmentSlot());
return;
}
this.getItem().onUseTick(level, livingEntity, this, ticksRemaining);
}
public void onDestroyed(ItemEntity itemEntity) {
this.getItem().onDestroyed(itemEntity);
}
public boolean canBeHurtBy(DamageSource source) {
DamageResistant damageResistant = this.get(DataComponents.DAMAGE_RESISTANT);
return damageResistant == null || !damageResistant.isResistantTo(source);
}
public boolean isValidRepairItem(ItemStack repairItem) {
Repairable repairable = this.get(DataComponents.REPAIRABLE);
return repairable != null && repairable.isValidRepairItem(repairItem);
}
public boolean canDestroyBlock(BlockState state, Level level, BlockPos pos, Player player) {
return this.getItem().canDestroyBlock(this, state, level, pos, player);
}
public DamageSource getDamageSource(LivingEntity attacker, Supplier<DamageSource> defaultSource) {
return Optional.ofNullable(this.get(DataComponents.DAMAGE_TYPE)).flatMap(holder -> holder.unwrap(attacker.registryAccess())).map(type -> new DamageSource((Holder<DamageType>)type, attacker)).or(() -> Optional.ofNullable(this.getItem().getItemDamageSource(attacker))).orElseGet(defaultSource);
}
}