package net.minecraft.world.item; import java.util.List; import java.util.function.Predicate; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; public class BowItem extends ProjectileWeaponItem { public static final int MAX_DRAW_DURATION = 20; public static final int DEFAULT_RANGE = 15; public BowItem(Item.Properties properties) { super(properties); } @Override public boolean releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeLeft) { if (!(entity instanceof Player player)) { return false; } else { ItemStack itemStack = player.getProjectile(stack); if (itemStack.isEmpty()) { return false; } else { int i = this.getUseDuration(stack, entity) - timeLeft; float f = getPowerForTime(i); if (f < 0.1) { return false; } else { List list = draw(stack, itemStack, player); if (level instanceof ServerLevel serverLevel && !list.isEmpty()) { this.shoot(serverLevel, player, player.getUsedItemHand(), stack, list, f * 3.0F, 1.0F, f == 1.0F, null); } level.playSound( null, player.getX(), player.getY(), player.getZ(), SoundEvents.ARROW_SHOOT, SoundSource.PLAYERS, 1.0F, 1.0F / (level.getRandom().nextFloat() * 0.4F + 1.2F) + f * 0.5F ); player.awardStat(Stats.ITEM_USED.get(this)); return true; } } } } @Override protected void shootProjectile( LivingEntity shooter, Projectile projectile, int index, float velocity, float inaccuracy, float angle, @Nullable LivingEntity target ) { projectile.shootFromRotation(shooter, shooter.getXRot(), shooter.getYRot() + angle, 0.0F, velocity, inaccuracy); } /** * Gets the velocity of the arrow entity from the bow's charge */ public static float getPowerForTime(int charge) { float f = charge / 20.0F; f = (f * f + f * 2.0F) / 3.0F; if (f > 1.0F) { f = 1.0F; } return f; } @Override public int getUseDuration(ItemStack stack, LivingEntity entity) { return 72000; } @Override public ItemUseAnimation getUseAnimation(ItemStack stack) { return ItemUseAnimation.BOW; } @Override public InteractionResult use(Level level, Player player, InteractionHand hand) { ItemStack itemStack = player.getItemInHand(hand); boolean bl = !player.getProjectile(itemStack).isEmpty(); if (!player.hasInfiniteMaterials() && !bl) { return InteractionResult.FAIL; } else { player.startUsingItem(hand); return InteractionResult.CONSUME; } } @Override public Predicate getAllSupportedProjectiles() { return ARROW_ONLY; } @Override public int getDefaultProjectileRange() { return 15; } }