package net.minecraft.world.entity.projectile; import com.google.common.collect.Lists; import com.mojang.serialization.Codec; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import java.util.List; import java.util.Objects; import javax.annotation.Nullable; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.BlockPos; import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundGameEventPacket; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.RegistryOps; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.EntityTypeTags; import net.minecraft.util.Mth; import net.minecraft.util.Unit; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MoverType; import net.minecraft.world.entity.OminousItemSpawner; import net.minecraft.world.entity.SlotAccess; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; public abstract class AbstractArrow extends Projectile { private static final double ARROW_BASE_DAMAGE = 2.0; private static final int SHAKE_TIME = 7; private static final float WATER_INERTIA = 0.6F; private static final float INERTIA = 0.99F; private static final short DEFAULT_LIFE = 0; private static final byte DEFAULT_SHAKE = 0; private static final boolean DEFAULT_IN_GROUND = false; private static final boolean DEFAULT_CRIT = false; private static final byte DEFAULT_PIERCE_LEVEL = 0; private static final EntityDataAccessor ID_FLAGS = SynchedEntityData.defineId(AbstractArrow.class, EntityDataSerializers.BYTE); private static final EntityDataAccessor PIERCE_LEVEL = SynchedEntityData.defineId(AbstractArrow.class, EntityDataSerializers.BYTE); private static final EntityDataAccessor IN_GROUND = SynchedEntityData.defineId(AbstractArrow.class, EntityDataSerializers.BOOLEAN); private static final int FLAG_CRIT = 1; private static final int FLAG_NOPHYSICS = 2; @Nullable private BlockState lastState; protected int inGroundTime; public AbstractArrow.Pickup pickup = AbstractArrow.Pickup.DISALLOWED; public int shakeTime = 0; private int life = 0; private double baseDamage = 2.0; private SoundEvent soundEvent = this.getDefaultHitGroundSoundEvent(); @Nullable private IntOpenHashSet piercingIgnoreEntityIds; @Nullable private List piercedAndKilledEntities; private ItemStack pickupItemStack = this.getDefaultPickupItem(); @Nullable private ItemStack firedFromWeapon = null; protected AbstractArrow(EntityType p_332730_, Level p_335646_) { super(p_332730_, p_335646_); } protected AbstractArrow( EntityType p_36721_, double p_343835_, double p_344593_, double p_344772_, Level p_36722_, ItemStack p_309639_, @Nullable ItemStack p_343861_ ) { this(p_36721_, p_36722_); this.pickupItemStack = p_309639_.copy(); this.applyComponentsFromItemStack(p_309639_); Unit unit = p_309639_.remove(DataComponents.INTANGIBLE_PROJECTILE); if (unit != null) { this.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; } this.setPos(p_343835_, p_344593_, p_344772_); if (p_343861_ != null && p_36722_ instanceof ServerLevel serverlevel) { if (p_343861_.isEmpty()) { throw new IllegalArgumentException("Invalid weapon firing an arrow"); } this.firedFromWeapon = p_343861_.copy(); int i = EnchantmentHelper.getPiercingCount(serverlevel, p_343861_, this.pickupItemStack); if (i > 0) { this.setPierceLevel((byte)i); } } } protected AbstractArrow( EntityType p_36711_, LivingEntity p_342675_, Level p_36715_, ItemStack p_310436_, @Nullable ItemStack p_343107_ ) { this(p_36711_, p_342675_.getX(), p_342675_.getEyeY() - 0.1F, p_342675_.getZ(), p_36715_, p_310436_, p_343107_); this.setOwner(p_342675_); } public void setSoundEvent(SoundEvent p_36741_) { this.soundEvent = p_36741_; } @Override public boolean shouldRenderAtSqrDistance(double p_36726_) { double d0 = this.getBoundingBox().getSize() * 10.0; if (Double.isNaN(d0)) { d0 = 1.0; } d0 *= 64.0 * getViewScale(); return p_36726_ < d0 * d0; } @Override protected void defineSynchedData(SynchedEntityData.Builder p_334076_) { p_334076_.define(ID_FLAGS, (byte)0); p_334076_.define(PIERCE_LEVEL, (byte)0); p_334076_.define(IN_GROUND, false); } @Override public void shoot(double p_36775_, double p_36776_, double p_36777_, float p_36778_, float p_36779_) { super.shoot(p_36775_, p_36776_, p_36777_, p_36778_, p_36779_); this.life = 0; } @Override public void lerpMotion(double p_36786_, double p_36787_, double p_36788_) { super.lerpMotion(p_36786_, p_36787_, p_36788_); this.life = 0; if (this.isInGround() && Mth.lengthSquared(p_36786_, p_36787_, p_36788_) > 0.0) { this.setInGround(false); } } @Override public void onSyncedDataUpdated(EntityDataAccessor p_370055_) { super.onSyncedDataUpdated(p_370055_); if (!this.firstTick && this.shakeTime <= 0 && p_370055_.equals(IN_GROUND) && this.isInGround()) { this.shakeTime = 7; } } @Override public void tick() { boolean flag = !this.isNoPhysics(); Vec3 vec3 = this.getDeltaMovement(); BlockPos blockpos = this.blockPosition(); BlockState blockstate = this.level().getBlockState(blockpos); if (!blockstate.isAir() && flag) { VoxelShape voxelshape = blockstate.getCollisionShape(this.level(), blockpos); if (!voxelshape.isEmpty()) { Vec3 vec31 = this.position(); for (AABB aabb : voxelshape.toAabbs()) { if (aabb.move(blockpos).contains(vec31)) { this.setDeltaMovement(Vec3.ZERO); this.setInGround(true); break; } } } } if (this.shakeTime > 0) { this.shakeTime--; } if (this.isInWaterOrRain() || blockstate.is(Blocks.POWDER_SNOW)) { this.clearFire(); } if (this.isInGround() && flag) { if (!this.level().isClientSide()) { if (this.lastState != blockstate && this.shouldFall()) { this.startFalling(); } else { this.tickDespawn(); } } this.inGroundTime++; if (this.isAlive()) { this.applyEffectsFromBlocks(); } if (!this.level().isClientSide) { this.setSharedFlagOnFire(this.getRemainingFireTicks() > 0); } } else { this.inGroundTime = 0; Vec3 vec32 = this.position(); if (this.isInWater()) { this.applyInertia(this.getWaterInertia()); this.addBubbleParticles(vec32); } if (this.isCritArrow()) { for (int i = 0; i < 4; i++) { this.level() .addParticle( ParticleTypes.CRIT, vec32.x + vec3.x * i / 4.0, vec32.y + vec3.y * i / 4.0, vec32.z + vec3.z * i / 4.0, -vec3.x, -vec3.y + 0.2, -vec3.z ); } } float f; if (!flag) { f = (float)(Mth.atan2(-vec3.x, -vec3.z) * 180.0F / (float)Math.PI); } else { f = (float)(Mth.atan2(vec3.x, vec3.z) * 180.0F / (float)Math.PI); } float f1 = (float)(Mth.atan2(vec3.y, vec3.horizontalDistance()) * 180.0F / (float)Math.PI); this.setXRot(lerpRotation(this.getXRot(), f1)); this.setYRot(lerpRotation(this.getYRot(), f)); if (flag) { BlockHitResult blockhitresult = this.level() .clipIncludingBorder(new ClipContext(vec32, vec32.add(vec3), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)); this.stepMoveAndHit(blockhitresult); } else { this.setPos(vec32.add(vec3)); this.applyEffectsFromBlocks(); } if (!this.isInWater()) { this.applyInertia(0.99F); } if (flag && !this.isInGround()) { this.applyGravity(); } super.tick(); } } private void stepMoveAndHit(BlockHitResult p_365483_) { while (this.isAlive()) { Vec3 vec3 = this.position(); EntityHitResult entityhitresult = this.findHitEntity(vec3, p_365483_.getLocation()); Vec3 vec31 = Objects.requireNonNullElse(entityhitresult, p_365483_).getLocation(); this.setPos(vec31); this.applyEffectsFromBlocks(vec3, vec31); if (this.portalProcess != null && this.portalProcess.isInsidePortalThisTick()) { this.handlePortal(); } if (entityhitresult == null) { if (this.isAlive() && p_365483_.getType() != HitResult.Type.MISS) { this.hitTargetOrDeflectSelf(p_365483_); this.hasImpulse = true; } break; } else if (this.isAlive() && !this.noPhysics) { ProjectileDeflection projectiledeflection = this.hitTargetOrDeflectSelf(entityhitresult); this.hasImpulse = true; if (this.getPierceLevel() > 0 && projectiledeflection == ProjectileDeflection.NONE) { continue; } break; } } } private void applyInertia(float p_375588_) { Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(vec3.scale(p_375588_)); } private void addBubbleParticles(Vec3 p_363513_) { Vec3 vec3 = this.getDeltaMovement(); for (int i = 0; i < 4; i++) { float f = 0.25F; this.level() .addParticle( ParticleTypes.BUBBLE, p_363513_.x - vec3.x * 0.25, p_363513_.y - vec3.y * 0.25, p_363513_.z - vec3.z * 0.25, vec3.x, vec3.y, vec3.z ); } } @Override protected double getDefaultGravity() { return 0.05; } private boolean shouldFall() { return this.isInGround() && this.level().noCollision(new AABB(this.position(), this.position()).inflate(0.06)); } private void startFalling() { this.setInGround(false); Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(vec3.multiply(this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F, this.random.nextFloat() * 0.2F)); this.life = 0; } protected boolean isInGround() { return this.entityData.get(IN_GROUND); } protected void setInGround(boolean p_366805_) { this.entityData.set(IN_GROUND, p_366805_); } @Override public boolean isPushedByFluid() { return !this.isInGround(); } @Override public void move(MoverType p_36749_, Vec3 p_36750_) { super.move(p_36749_, p_36750_); if (p_36749_ != MoverType.SELF && this.shouldFall()) { this.startFalling(); } } protected void tickDespawn() { this.life++; if (this.life >= 1200) { this.discard(); } } private void resetPiercedEntities() { if (this.piercedAndKilledEntities != null) { this.piercedAndKilledEntities.clear(); } if (this.piercingIgnoreEntityIds != null) { this.piercingIgnoreEntityIds.clear(); } } @Override protected void onItemBreak(Item p_369255_) { this.firedFromWeapon = null; } @Override public void onAboveBubbleColumn(boolean p_395389_, BlockPos p_396993_) { if (!this.isInGround()) { super.onAboveBubbleColumn(p_395389_, p_396993_); } } @Override public void onInsideBubbleColumn(boolean p_376658_) { if (!this.isInGround()) { super.onInsideBubbleColumn(p_376658_); } } @Override public void push(double p_377928_, double p_377558_, double p_376841_) { if (!this.isInGround()) { super.push(p_377928_, p_377558_, p_376841_); } } @Override protected void onHitEntity(EntityHitResult p_36757_) { super.onHitEntity(p_36757_); Entity entity = p_36757_.getEntity(); float f = (float)this.getDeltaMovement().length(); double d0 = this.baseDamage; Entity entity1 = this.getOwner(); DamageSource damagesource = this.damageSources().arrow(this, (Entity)(entity1 != null ? entity1 : this)); if (this.getWeaponItem() != null && this.level() instanceof ServerLevel serverlevel) { d0 = EnchantmentHelper.modifyDamage(serverlevel, this.getWeaponItem(), entity, damagesource, (float)d0); } int j = Mth.ceil(Mth.clamp(f * d0, 0.0, 2.147483647E9)); if (this.getPierceLevel() > 0) { if (this.piercingIgnoreEntityIds == null) { this.piercingIgnoreEntityIds = new IntOpenHashSet(5); } if (this.piercedAndKilledEntities == null) { this.piercedAndKilledEntities = Lists.newArrayListWithCapacity(5); } if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) { this.discard(); return; } this.piercingIgnoreEntityIds.add(entity.getId()); } if (this.isCritArrow()) { long k = this.random.nextInt(j / 2 + 2); j = (int)Math.min(k + j, 2147483647L); } if (entity1 instanceof LivingEntity livingentity1) { livingentity1.setLastHurtMob(entity); } boolean flag = entity.getType() == EntityType.ENDERMAN; int i = entity.getRemainingFireTicks(); if (this.isOnFire() && !flag) { entity.igniteForSeconds(5.0F); } if (entity.hurtOrSimulate(damagesource, j)) { if (flag) { return; } if (entity instanceof LivingEntity livingentity) { if (!this.level().isClientSide && this.getPierceLevel() <= 0) { livingentity.setArrowCount(livingentity.getArrowCount() + 1); } this.doKnockback(livingentity, damagesource); if (this.level() instanceof ServerLevel serverlevel1) { EnchantmentHelper.doPostAttackEffectsWithItemSource(serverlevel1, livingentity, damagesource, this.getWeaponItem()); } this.doPostHurtEffects(livingentity); if (livingentity instanceof Player && entity1 instanceof ServerPlayer serverplayer && !this.isSilent() && livingentity != serverplayer) { serverplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.PLAY_ARROW_HIT_SOUND, 0.0F)); } if (!entity.isAlive() && this.piercedAndKilledEntities != null) { this.piercedAndKilledEntities.add(livingentity); } if (!this.level().isClientSide && entity1 instanceof ServerPlayer serverplayer1) { if (this.piercedAndKilledEntities != null) { CriteriaTriggers.KILLED_BY_ARROW.trigger(serverplayer1, this.piercedAndKilledEntities, this.firedFromWeapon); } else if (!entity.isAlive()) { CriteriaTriggers.KILLED_BY_ARROW.trigger(serverplayer1, List.of(entity), this.firedFromWeapon); } } } this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); if (this.getPierceLevel() <= 0) { this.discard(); } } else { entity.setRemainingFireTicks(i); this.deflect(ProjectileDeflection.REVERSE, entity, this.getOwner(), false); this.setDeltaMovement(this.getDeltaMovement().scale(0.2)); if (this.level() instanceof ServerLevel serverlevel2 && this.getDeltaMovement().lengthSqr() < 1.0E-7) { if (this.pickup == AbstractArrow.Pickup.ALLOWED) { this.spawnAtLocation(serverlevel2, this.getPickupItem(), 0.1F); } this.discard(); } } } protected void doKnockback(LivingEntity p_342292_, DamageSource p_345063_) { double d0 = this.firedFromWeapon != null && this.level() instanceof ServerLevel serverlevel ? EnchantmentHelper.modifyKnockback(serverlevel, this.firedFromWeapon, p_342292_, p_345063_, 0.0F) : 0.0F; if (d0 > 0.0) { double d1 = Math.max(0.0, 1.0 - p_342292_.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)); Vec3 vec3 = this.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(d0 * 0.6 * d1); if (vec3.lengthSqr() > 0.0) { p_342292_.push(vec3.x, 0.1, vec3.z); } } } @Override protected void onHitBlock(BlockHitResult p_36755_) { this.lastState = this.level().getBlockState(p_36755_.getBlockPos()); super.onHitBlock(p_36755_); ItemStack itemstack = this.getWeaponItem(); if (this.level() instanceof ServerLevel serverlevel && itemstack != null) { this.hitBlockEnchantmentEffects(serverlevel, p_36755_, itemstack); } Vec3 vec31 = this.getDeltaMovement(); Vec3 vec32 = new Vec3(Math.signum(vec31.x), Math.signum(vec31.y), Math.signum(vec31.z)); Vec3 vec3 = vec32.scale(0.05F); this.setPos(this.position().subtract(vec3)); this.setDeltaMovement(Vec3.ZERO); this.playSound(this.getHitGroundSoundEvent(), 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F)); this.setInGround(true); this.shakeTime = 7; this.setCritArrow(false); this.setPierceLevel((byte)0); this.setSoundEvent(SoundEvents.ARROW_HIT); this.resetPiercedEntities(); } protected void hitBlockEnchantmentEffects(ServerLevel p_344773_, BlockHitResult p_343962_, ItemStack p_342314_) { Vec3 vec3 = p_343962_.getBlockPos().clampLocationWithin(p_343962_.getLocation()); EnchantmentHelper.onHitBlock( p_344773_, p_342314_, this.getOwner() instanceof LivingEntity livingentity ? livingentity : null, this, null, vec3, p_344773_.getBlockState(p_343962_.getBlockPos()), p_344325_ -> this.firedFromWeapon = null ); } @Override public ItemStack getWeaponItem() { return this.firedFromWeapon; } protected SoundEvent getDefaultHitGroundSoundEvent() { return SoundEvents.ARROW_HIT; } protected final SoundEvent getHitGroundSoundEvent() { return this.soundEvent; } protected void doPostHurtEffects(LivingEntity p_36744_) { } @Nullable protected EntityHitResult findHitEntity(Vec3 p_36758_, Vec3 p_36759_) { return ProjectileUtil.getEntityHitResult(this.level(), this, p_36758_, p_36759_, this.getBoundingBox().expandTowards(this.getDeltaMovement()).inflate(1.0), this::canHitEntity); } @Override protected boolean canHitEntity(Entity p_36743_) { return p_36743_ instanceof Player && this.getOwner() instanceof Player player && !player.canHarmPlayer((Player)p_36743_) ? false : super.canHitEntity(p_36743_) && (this.piercingIgnoreEntityIds == null || !this.piercingIgnoreEntityIds.contains(p_36743_.getId())); } @Override public void addAdditionalSaveData(CompoundTag p_36772_) { super.addAdditionalSaveData(p_36772_); RegistryOps registryops = this.registryAccess().createSerializationContext(NbtOps.INSTANCE); p_36772_.putShort("life", (short)this.life); p_36772_.storeNullable("inBlockState", BlockState.CODEC, registryops, this.lastState); p_36772_.putByte("shake", (byte)this.shakeTime); p_36772_.putBoolean("inGround", this.isInGround()); p_36772_.store("pickup", AbstractArrow.Pickup.LEGACY_CODEC, this.pickup); p_36772_.putDouble("damage", this.baseDamage); p_36772_.putBoolean("crit", this.isCritArrow()); p_36772_.putByte("PierceLevel", this.getPierceLevel()); p_36772_.store("SoundEvent", BuiltInRegistries.SOUND_EVENT.byNameCodec(), this.soundEvent); p_36772_.store("item", ItemStack.CODEC, registryops, this.pickupItemStack); p_36772_.storeNullable("weapon", ItemStack.CODEC, registryops, this.firedFromWeapon); } @Override public void readAdditionalSaveData(CompoundTag p_36761_) { super.readAdditionalSaveData(p_36761_); RegistryOps registryops = this.registryAccess().createSerializationContext(NbtOps.INSTANCE); this.life = p_36761_.getShortOr("life", (short)0); this.lastState = p_36761_.read("inBlockState", BlockState.CODEC, registryops).orElse(null); this.shakeTime = p_36761_.getByteOr("shake", (byte)0) & 255; this.setInGround(p_36761_.getBooleanOr("inGround", false)); this.baseDamage = p_36761_.getDoubleOr("damage", 2.0); this.pickup = p_36761_.read("pickup", AbstractArrow.Pickup.LEGACY_CODEC).orElse(AbstractArrow.Pickup.DISALLOWED); this.setCritArrow(p_36761_.getBooleanOr("crit", false)); this.setPierceLevel(p_36761_.getByteOr("PierceLevel", (byte)0)); this.soundEvent = p_36761_.read("SoundEvent", BuiltInRegistries.SOUND_EVENT.byNameCodec()).orElse(this.getDefaultHitGroundSoundEvent()); this.setPickupItemStack(p_36761_.read("item", ItemStack.CODEC, registryops).orElse(this.getDefaultPickupItem())); this.firedFromWeapon = p_36761_.read("weapon", ItemStack.CODEC, registryops).orElse(null); } @Override public void setOwner(@Nullable Entity p_36770_) { super.setOwner(p_36770_); this.pickup = switch (p_36770_) { case Player player when this.pickup == AbstractArrow.Pickup.DISALLOWED -> AbstractArrow.Pickup.ALLOWED; case OminousItemSpawner ominousitemspawner -> AbstractArrow.Pickup.DISALLOWED; case null, default -> this.pickup; }; } @Override public void playerTouch(Player p_36766_) { if (!this.level().isClientSide && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) { if (this.tryPickup(p_36766_)) { p_36766_.take(this, 1); this.discard(); } } } protected boolean tryPickup(Player p_150121_) { return switch (this.pickup) { case DISALLOWED -> false; case ALLOWED -> p_150121_.getInventory().add(this.getPickupItem()); case CREATIVE_ONLY -> p_150121_.hasInfiniteMaterials(); }; } protected ItemStack getPickupItem() { return this.pickupItemStack.copy(); } protected abstract ItemStack getDefaultPickupItem(); @Override protected Entity.MovementEmission getMovementEmission() { return Entity.MovementEmission.NONE; } public ItemStack getPickupItemStackOrigin() { return this.pickupItemStack; } public void setBaseDamage(double p_36782_) { this.baseDamage = p_36782_; } @Override public boolean isAttackable() { return this.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE); } public void setCritArrow(boolean p_36763_) { this.setFlag(1, p_36763_); } private void setPierceLevel(byte p_36768_) { this.entityData.set(PIERCE_LEVEL, p_36768_); } private void setFlag(int p_36738_, boolean p_36739_) { byte b0 = this.entityData.get(ID_FLAGS); if (p_36739_) { this.entityData.set(ID_FLAGS, (byte)(b0 | p_36738_)); } else { this.entityData.set(ID_FLAGS, (byte)(b0 & ~p_36738_)); } } protected void setPickupItemStack(ItemStack p_329565_) { if (!p_329565_.isEmpty()) { this.pickupItemStack = p_329565_; } else { this.pickupItemStack = this.getDefaultPickupItem(); } } public boolean isCritArrow() { byte b0 = this.entityData.get(ID_FLAGS); return (b0 & 1) != 0; } public byte getPierceLevel() { return this.entityData.get(PIERCE_LEVEL); } public void setBaseDamageFromMob(float p_345045_) { this.setBaseDamage(p_345045_ * 2.0F + this.random.triangle(this.level().getDifficulty().getId() * 0.11, 0.57425)); } protected float getWaterInertia() { return 0.6F; } public void setNoPhysics(boolean p_36791_) { this.noPhysics = p_36791_; this.setFlag(2, p_36791_); } public boolean isNoPhysics() { return !this.level().isClientSide ? this.noPhysics : (this.entityData.get(ID_FLAGS) & 2) != 0; } @Override public boolean isPickable() { return super.isPickable() && !this.isInGround(); } @Override public SlotAccess getSlot(int p_330583_) { return p_330583_ == 0 ? SlotAccess.of(this::getPickupItemStackOrigin, this::setPickupItemStack) : super.getSlot(p_330583_); } @Override protected boolean shouldBounceOnWorldBorder() { return true; } public static enum Pickup { DISALLOWED, ALLOWED, CREATIVE_ONLY; public static final Codec LEGACY_CODEC = Codec.BYTE.xmap(AbstractArrow.Pickup::byOrdinal, p_391413_ -> (byte)p_391413_.ordinal()); public static AbstractArrow.Pickup byOrdinal(int p_36809_) { if (p_36809_ < 0 || p_36809_ > values().length) { p_36809_ = 0; } return values()[p_36809_]; } } }