package net.minecraft.world.item; import java.util.List; import java.util.Optional; import net.minecraft.ChatFormatting; import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.stats.Stats; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.SlotAccess; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ClickAction; import net.minecraft.world.inventory.Slot; import net.minecraft.world.inventory.tooltip.BundleTooltip; import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.item.component.BundleContents; import net.minecraft.world.level.Level; import org.apache.commons.lang3.math.Fraction; public class BundleItem extends Item { private static final int BAR_COLOR = Mth.color(0.4F, 0.4F, 1.0F); private static final int TOOLTIP_MAX_WEIGHT = 64; public BundleItem(Item.Properties properties) { super(properties); } public static float getFullnessDisplay(ItemStack stack) { BundleContents bundleContents = stack.getOrDefault(DataComponents.BUNDLE_CONTENTS, BundleContents.EMPTY); return bundleContents.weight().floatValue(); } @Override public boolean overrideStackedOnOther(ItemStack stack, Slot slot, ClickAction action, Player player) { if (action != ClickAction.SECONDARY) { return false; } else { BundleContents bundleContents = stack.get(DataComponents.BUNDLE_CONTENTS); if (bundleContents == null) { return false; } else { ItemStack itemStack = slot.getItem(); BundleContents.Mutable mutable = new BundleContents.Mutable(bundleContents); if (itemStack.isEmpty()) { this.playRemoveOneSound(player); ItemStack itemStack2 = mutable.removeOne(); if (itemStack2 != null) { ItemStack itemStack3 = slot.safeInsert(itemStack2); mutable.tryInsert(itemStack3); } } else if (itemStack.getItem().canFitInsideContainerItems()) { int i = mutable.tryTransfer(slot, player); if (i > 0) { this.playInsertSound(player); } } stack.set(DataComponents.BUNDLE_CONTENTS, mutable.toImmutable()); return true; } } } @Override public boolean overrideOtherStackedOnMe(ItemStack stack, ItemStack other, Slot slot, ClickAction action, Player player, SlotAccess access) { if (action == ClickAction.SECONDARY && slot.allowModification(player)) { BundleContents bundleContents = stack.get(DataComponents.BUNDLE_CONTENTS); if (bundleContents == null) { return false; } else { BundleContents.Mutable mutable = new BundleContents.Mutable(bundleContents); if (other.isEmpty()) { ItemStack itemStack = mutable.removeOne(); if (itemStack != null) { this.playRemoveOneSound(player); access.set(itemStack); } } else { int i = mutable.tryInsert(other); if (i > 0) { this.playInsertSound(player); } } stack.set(DataComponents.BUNDLE_CONTENTS, mutable.toImmutable()); return true; } } else { return false; } } @Override public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { ItemStack itemStack = player.getItemInHand(usedHand); if (dropContents(itemStack, player)) { this.playDropContentsSound(player); player.awardStat(Stats.ITEM_USED.get(this)); return InteractionResultHolder.sidedSuccess(itemStack, level.isClientSide()); } else { return InteractionResultHolder.fail(itemStack); } } @Override public boolean isBarVisible(ItemStack stack) { BundleContents bundleContents = stack.getOrDefault(DataComponents.BUNDLE_CONTENTS, BundleContents.EMPTY); return bundleContents.weight().compareTo(Fraction.ZERO) > 0; } @Override public int getBarWidth(ItemStack stack) { BundleContents bundleContents = stack.getOrDefault(DataComponents.BUNDLE_CONTENTS, BundleContents.EMPTY); return Math.min(1 + Mth.mulAndTruncate(bundleContents.weight(), 12), 13); } @Override public int getBarColor(ItemStack stack) { return BAR_COLOR; } private static boolean dropContents(ItemStack stack, Player player) { BundleContents bundleContents = stack.get(DataComponents.BUNDLE_CONTENTS); if (bundleContents != null && !bundleContents.isEmpty()) { stack.set(DataComponents.BUNDLE_CONTENTS, BundleContents.EMPTY); if (player instanceof ServerPlayer) { bundleContents.itemsCopy().forEach(itemStack -> player.drop(itemStack, true)); } return true; } else { return false; } } @Override public Optional getTooltipImage(ItemStack stack) { return !stack.has(DataComponents.HIDE_TOOLTIP) && !stack.has(DataComponents.HIDE_ADDITIONAL_TOOLTIP) ? Optional.ofNullable(stack.get(DataComponents.BUNDLE_CONTENTS)).map(BundleTooltip::new) : Optional.empty(); } @Override public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltipComponents, TooltipFlag tooltipFlag) { BundleContents bundleContents = stack.get(DataComponents.BUNDLE_CONTENTS); if (bundleContents != null) { int i = Mth.mulAndTruncate(bundleContents.weight(), 64); tooltipComponents.add(Component.translatable("item.minecraft.bundle.fullness", i, 64).withStyle(ChatFormatting.GRAY)); } } @Override public void onDestroyed(ItemEntity itemEntity) { BundleContents bundleContents = itemEntity.getItem().get(DataComponents.BUNDLE_CONTENTS); if (bundleContents != null) { itemEntity.getItem().set(DataComponents.BUNDLE_CONTENTS, BundleContents.EMPTY); ItemUtils.onContainerDestroyed(itemEntity, bundleContents.itemsCopy()); } } private void playRemoveOneSound(Entity entity) { entity.playSound(SoundEvents.BUNDLE_REMOVE_ONE, 0.8F, 0.8F + entity.level().getRandom().nextFloat() * 0.4F); } private void playInsertSound(Entity entity) { entity.playSound(SoundEvents.BUNDLE_INSERT, 0.8F, 0.8F + entity.level().getRandom().nextFloat() * 0.4F); } private void playDropContentsSound(Entity entity) { entity.playSound(SoundEvents.BUNDLE_DROP_CONTENTS, 0.8F, 0.8F + entity.level().getRandom().nextFloat() * 0.4F); } }