--- a/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -3,6 +3,8 @@
 import com.google.common.collect.Lists;
 import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import javax.annotation.Nullable;
 import net.minecraft.advancements.CriteriaTriggers;
@@ -28,6 +30,7 @@
 import net.minecraft.world.entity.MoverType;
 import net.minecraft.world.entity.Pose;
 import net.minecraft.world.entity.ai.attributes.Attributes;
+import net.minecraft.world.entity.item.ItemEntity;
 import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.enchantment.EnchantmentHelper;
@@ -42,8 +45,12 @@
 import net.minecraft.world.phys.HitResult;
 import net.minecraft.world.phys.Vec3;
 import net.minecraft.world.phys.shapes.VoxelShape;
+import org.bukkit.event.entity.EntityCombustByEntityEvent;
+import org.bukkit.event.player.PlayerPickupArrowEvent;
+// CraftBukkit end
 
 public abstract class AbstractArrow extends Projectile {
+
     private static final double ARROW_BASE_DAMAGE = 2.0D;
     private static final EntityDataAccessor<Byte> ID_FLAGS = SynchedEntityData.defineId(AbstractArrow.class, EntityDataSerializers.BYTE);
     private static final EntityDataAccessor<Byte> PIERCE_LEVEL = SynchedEntityData.defineId(AbstractArrow.class, EntityDataSerializers.BYTE);
@@ -54,19 +61,34 @@
     private BlockState lastState;
     public boolean inGround;
     protected int inGroundTime;
-    public AbstractArrow.Pickup pickup = AbstractArrow.Pickup.DISALLOWED;
+    public AbstractArrow.Pickup pickup;
     public int shakeTime;
     public int life;
-    private double baseDamage = 2.0D;
+    private double baseDamage;
     public int knockback;
-    private SoundEvent soundEvent = this.getDefaultHitGroundSoundEvent();
+    private SoundEvent soundEvent;
     @Nullable
     private IntOpenHashSet piercingIgnoreEntityIds;
     @Nullable
     private List<Entity> piercedAndKilledEntities;
 
+    // Spigot Start
+    @Override
+    public void inactiveTick()
+    {
+        if ( this.inGround )
+        {
+            this.life += 1;
+        }
+        super.inactiveTick();
+    }
+    // Spigot End
+
     protected AbstractArrow(EntityType<? extends AbstractArrow> type, Level world) {
         super(type, world);
+        this.pickup = AbstractArrow.Pickup.DISALLOWED;
+        this.baseDamage = 2.0D;
+        this.soundEvent = this.getDefaultHitGroundSoundEvent();
     }
 
     protected AbstractArrow(EntityType<? extends AbstractArrow> type, double x, double y, double z, Level world) {
@@ -75,7 +97,7 @@
     }
 
     protected AbstractArrow(EntityType<? extends AbstractArrow> type, LivingEntity owner, Level world) {
-        this(type, owner.getX(), owner.getEyeY() - (double)0.1F, owner.getZ(), world);
+        this(type, owner.getX(), owner.getEyeY() - 0.10000000149011612D, owner.getZ(), world);
         this.setOwner(owner);
         if (owner instanceof Player) {
             this.pickup = AbstractArrow.Pickup.ALLOWED;
@@ -89,19 +111,20 @@
 
     @Override
     public boolean shouldRenderAtSqrDistance(double distance) {
-        double d = this.getBoundingBox().getSize() * 10.0D;
-        if (Double.isNaN(d)) {
-            d = 1.0D;
+        double d1 = this.getBoundingBox().getSize() * 10.0D;
+
+        if (Double.isNaN(d1)) {
+            d1 = 1.0D;
         }
 
-        d *= 64.0D * getViewScale();
-        return distance < d * d;
+        d1 *= 64.0D * getViewScale();
+        return distance < d1 * d1;
     }
 
     @Override
     protected void defineSynchedData() {
-        this.entityData.define(ID_FLAGS, (byte)0);
-        this.entityData.define(PIERCE_LEVEL, (byte)0);
+        this.entityData.define(AbstractArrow.ID_FLAGS, (byte) 0);
+        this.entityData.define(AbstractArrow.PIERCE_LEVEL, (byte) 0);
     }
 
     @Override
@@ -125,25 +148,33 @@
     @Override
     public void tick() {
         super.tick();
-        boolean bl = this.isNoPhysics();
-        Vec3 vec3 = this.getDeltaMovement();
+        boolean flag = this.isNoPhysics();
+        Vec3 vec3d = this.getDeltaMovement();
+
         if (this.xRotO == 0.0F && this.yRotO == 0.0F) {
-            double d = vec3.horizontalDistance();
-            this.setYRot((float)(Mth.atan2(vec3.x, vec3.z) * (double)(180F / (float)Math.PI)));
-            this.setXRot((float)(Mth.atan2(vec3.y, d) * (double)(180F / (float)Math.PI)));
+            double d0 = vec3d.horizontalDistance();
+
+            this.setYRot((float) (Mth.atan2(vec3d.x, vec3d.z) * 57.2957763671875D));
+            this.setXRot((float) (Mth.atan2(vec3d.y, d0) * 57.2957763671875D));
             this.yRotO = this.getYRot();
             this.xRotO = this.getXRot();
         }
 
-        BlockPos blockPos = this.blockPosition();
-        BlockState blockState = this.level.getBlockState(blockPos);
-        if (!blockState.isAir() && !bl) {
-            VoxelShape voxelShape = blockState.getCollisionShape(this.level, blockPos);
-            if (!voxelShape.isEmpty()) {
-                Vec3 vec32 = this.position();
+        BlockPos blockposition = this.blockPosition();
+        BlockState iblockdata = this.level.getBlockState(blockposition);
+        Vec3 vec3d1;
 
-                for(AABB aABB : voxelShape.toAabbs()) {
-                    if (aABB.move(blockPos).contains(vec32)) {
+        if (!iblockdata.isAir() && !flag) {
+            VoxelShape voxelshape = iblockdata.getCollisionShape(this.level, blockposition);
+
+            if (!voxelshape.isEmpty()) {
+                vec3d1 = this.position();
+                Iterator iterator = voxelshape.toAabbs().iterator();
+
+                while (iterator.hasNext()) {
+                    AABB axisalignedbb = (AABB) iterator.next();
+
+                    if (axisalignedbb.move(blockposition).contains(vec3d1)) {
                         this.inGround = true;
                         break;
                     }
@@ -155,12 +186,12 @@
             --this.shakeTime;
         }
 
-        if (this.isInWaterOrRain() || blockState.is(Blocks.POWDER_SNOW)) {
+        if (this.isInWaterOrRain() || iblockdata.is(Blocks.POWDER_SNOW)) {
             this.clearFire();
         }
 
-        if (this.inGround && !bl) {
-            if (this.lastState != blockState && this.shouldFall()) {
+        if (this.inGround && !flag) {
+            if (this.lastState != iblockdata && this.shouldFall()) {
                 this.startFalling();
             } else if (!this.level.isClientSide) {
                 this.tickDespawn();
@@ -168,94 +199,129 @@
 
             ++this.inGroundTime;
         } else {
+            if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds
             this.inGroundTime = 0;
-            Vec3 vec33 = this.position();
-            Vec3 vec34 = vec33.add(vec3);
-            HitResult hitResult = this.level.clip(new ClipContext(vec33, vec34, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
-            if (hitResult.getType() != HitResult.Type.MISS) {
-                vec34 = hitResult.getLocation();
+            Vec3 vec3d2 = this.position();
+
+            vec3d1 = vec3d2.add(vec3d);
+            Object object = this.level.clip(new ClipContext(vec3d2, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this));
+
+            if (((HitResult) object).getType() != HitResult.Type.MISS) {
+                vec3d1 = ((HitResult) object).getLocation();
             }
 
-            while(!this.isRemoved()) {
-                EntityHitResult entityHitResult = this.findHitEntity(vec33, vec34);
-                if (entityHitResult != null) {
-                    hitResult = entityHitResult;
+            while (!this.isRemoved()) {
+                EntityHitResult movingobjectpositionentity = this.findHitEntity(vec3d2, vec3d1);
+
+                if (movingobjectpositionentity != null) {
+                    object = movingobjectpositionentity;
                 }
 
-                if (hitResult != null && hitResult.getType() == HitResult.Type.ENTITY) {
-                    Entity entity = ((EntityHitResult)hitResult).getEntity();
-                    Entity entity2 = this.getOwner();
-                    if (entity instanceof Player && entity2 instanceof Player && !((Player)entity2).canHarmPlayer((Player)entity)) {
-                        hitResult = null;
-                        entityHitResult = null;
+                if (object != null && ((HitResult) object).getType() == HitResult.Type.ENTITY) {
+                    Entity entity = ((EntityHitResult) object).getEntity();
+                    Entity entity1 = this.getOwner();
+
+                    if (entity instanceof Player && entity1 instanceof Player && !((Player) entity1).canHarmPlayer((Player) entity)) {
+                        object = null;
+                        movingobjectpositionentity = null;
                     }
                 }
 
-                if (hitResult != null && !bl) {
-                    this.onHit(hitResult);
+                // Paper start - Call ProjectileCollideEvent
+                // TODO: flag - noclip - call cancelled?
+                if (object instanceof EntityHitResult) {
+                    com.destroystokyo.paper.event.entity.ProjectileCollideEvent event = org.bukkit.craftbukkit.v1_19_R1.event.CraftEventFactory.callProjectileCollideEvent(this, (EntityHitResult)object);
+                    if (event.isCancelled()) {
+                        object = null;
+                        movingobjectpositionentity = null;
+                    }
+                }
+                // Paper end
+
+                if (object != null && !flag) {
+                    this.preOnHit((HitResult) object); // CraftBukkit - projectile hit event
                     this.hasImpulse = true;
                 }
 
-                if (entityHitResult == null || this.getPierceLevel() <= 0) {
+                if (movingobjectpositionentity == null || this.getPierceLevel() <= 0) {
                     break;
                 }
 
-                hitResult = null;
+                object = null;
             }
 
-            vec3 = this.getDeltaMovement();
-            double e = vec3.x;
-            double f = vec3.y;
-            double g = vec3.z;
+            vec3d = this.getDeltaMovement();
+            double d1 = vec3d.x;
+            double d2 = vec3d.y;
+            double d3 = vec3d.z;
+
             if (this.isCritArrow()) {
-                for(int i = 0; i < 4; ++i) {
-                    this.level.addParticle(ParticleTypes.CRIT, this.getX() + e * (double)i / 4.0D, this.getY() + f * (double)i / 4.0D, this.getZ() + g * (double)i / 4.0D, -e, -f + 0.2D, -g);
+                for (int i = 0; i < 4; ++i) {
+                    this.level.addParticle(ParticleTypes.CRIT, this.getX() + d1 * (double) i / 4.0D, this.getY() + d2 * (double) i / 4.0D, this.getZ() + d3 * (double) i / 4.0D, -d1, -d2 + 0.2D, -d3);
                 }
             }
 
-            double h = this.getX() + e;
-            double j = this.getY() + f;
-            double k = this.getZ() + g;
-            double l = vec3.horizontalDistance();
-            if (bl) {
-                this.setYRot((float)(Mth.atan2(-e, -g) * (double)(180F / (float)Math.PI)));
+            double d4 = this.getX() + d1;
+            double d5 = this.getY() + d2;
+            double d6 = this.getZ() + d3;
+            double d7 = vec3d.horizontalDistance();
+
+            if (flag) {
+                this.setYRot((float) (Mth.atan2(-d1, -d3) * 57.2957763671875D));
             } else {
-                this.setYRot((float)(Mth.atan2(e, g) * (double)(180F / (float)Math.PI)));
+                this.setYRot((float) (Mth.atan2(d1, d3) * 57.2957763671875D));
             }
 
-            this.setXRot((float)(Mth.atan2(f, l) * (double)(180F / (float)Math.PI)));
+            this.setXRot((float) (Mth.atan2(d2, d7) * 57.2957763671875D));
             this.setXRot(lerpRotation(this.xRotO, this.getXRot()));
             this.setYRot(lerpRotation(this.yRotO, this.getYRot()));
-            float m = 0.99F;
-            float n = 0.05F;
+            float f = 0.99F;
+            float f1 = 0.05F;
+
             if (this.isInWater()) {
-                for(int o = 0; o < 4; ++o) {
-                    float p = 0.25F;
-                    this.level.addParticle(ParticleTypes.BUBBLE, h - e * 0.25D, j - f * 0.25D, k - g * 0.25D, e, f, g);
+                for (int j = 0; j < 4; ++j) {
+                    float f2 = 0.25F;
+
+                    this.level.addParticle(ParticleTypes.BUBBLE, d4 - d1 * 0.25D, d5 - d2 * 0.25D, d6 - d3 * 0.25D, d1, d2, d3);
                 }
 
-                m = this.getWaterInertia();
+                f = this.getWaterInertia();
             }
 
-            this.setDeltaMovement(vec3.scale((double)m));
-            if (!this.isNoGravity() && !bl) {
-                Vec3 vec35 = this.getDeltaMovement();
-                this.setDeltaMovement(vec35.x, vec35.y - (double)0.05F, vec35.z);
+            this.setDeltaMovement(vec3d.scale((double) f));
+            if (!this.isNoGravity() && !flag) {
+                Vec3 vec3d3 = this.getDeltaMovement();
+
+                this.setDeltaMovement(vec3d3.x, vec3d3.y - 0.05000000074505806D, vec3d3.z);
             }
 
-            this.setPos(h, j, k);
+            this.setPos(d4, d5, d6);
             this.checkInsideBlocks();
         }
     }
 
+    // Paper start
+    @Override
+    protected void preOnHit(HitResult hitResult) {
+        super.preOnHit(hitResult);
+        if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) {
+            if (this.piercingIgnoreEntityIds == null) {
+                this.piercingIgnoreEntityIds = new IntOpenHashSet(5);
+            }
+            this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId());
+        }
+    }
+    // Paper end
+
     private boolean shouldFall() {
         return this.inGround && this.level.noCollision((new AABB(this.position(), this.position())).inflate(0.06D));
     }
 
     private void startFalling() {
         this.inGround = false;
-        Vec3 vec3 = this.getDeltaMovement();
-        this.setDeltaMovement(vec3.multiply((double)(this.random.nextFloat() * 0.2F), (double)(this.random.nextFloat() * 0.2F), (double)(this.random.nextFloat() * 0.2F)));
+        Vec3 vec3d = this.getDeltaMovement();
+
+        this.setDeltaMovement(vec3d.multiply((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F)));
         this.life = 0;
     }
 
@@ -270,7 +336,7 @@
 
     protected void tickDespawn() {
         ++this.life;
-        if (this.life >= 1200) {
+        if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? level.paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
             this.discard();
         }
 
@@ -291,8 +357,9 @@
     protected void onHitEntity(EntityHitResult entityHitResult) {
         super.onHitEntity(entityHitResult);
         Entity entity = entityHitResult.getEntity();
-        float f = (float)this.getDeltaMovement().length();
-        int i = Mth.ceil(Mth.clamp((double)f * this.baseDamage, 0.0D, 2.147483647E9D));
+        float f = (float) this.getDeltaMovement().length();
+        int i = Mth.ceil(Mth.clamp((double) f * this.baseDamage, 0.0D, 2.147483647E9D));
+
         if (this.getPierceLevel() > 0) {
             if (this.piercingIgnoreEntityIds == null) {
                 this.piercingIgnoreEntityIds = new IntOpenHashSet(5);
@@ -311,66 +378,79 @@
         }
 
         if (this.isCritArrow()) {
-            long l = (long)this.random.nextInt(i / 2 + 2);
-            i = (int)Math.min(l + (long)i, 2147483647L);
+            long j = (long) this.random.nextInt(i / 2 + 2);
+
+            i = (int) Math.min(j + (long) i, 2147483647L);
         }
 
-        Entity entity2 = this.getOwner();
-        DamageSource damageSource;
-        if (entity2 == null) {
-            damageSource = DamageSource.arrow(this, this);
+        Entity entity1 = this.getOwner();
+        DamageSource damagesource;
+
+        if (entity1 == null) {
+            damagesource = DamageSource.arrow(this, this);
         } else {
-            damageSource = DamageSource.arrow(this, entity2);
-            if (entity2 instanceof LivingEntity) {
-                ((LivingEntity)entity2).setLastHurtMob(entity);
+            damagesource = DamageSource.arrow(this, entity1);
+            if (entity1 instanceof LivingEntity) {
+                ((LivingEntity) entity1).setLastHurtMob(entity);
             }
         }
 
-        boolean bl = entity.getType() == EntityType.ENDERMAN;
-        int j = entity.getRemainingFireTicks();
-        if (this.isOnFire() && !bl) {
-            entity.setSecondsOnFire(5);
+        if (this.isCritArrow()) damagesource = damagesource.critical(); // Paper - add critical damage API
+        boolean flag = entity.getType() == EntityType.ENDERMAN;
+        int k = entity.getRemainingFireTicks();
+
+        if (this.isOnFire() && !flag) {
+            // CraftBukkit start
+            EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5);
+            org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent);
+            if (!combustEvent.isCancelled()) {
+                entity.setSecondsOnFire(combustEvent.getDuration(), false);
+            }
+            // CraftBukkit end
         }
 
-        if (entity.hurt(damageSource, (float)i)) {
-            if (bl) {
+        if (entity.hurt(damagesource, (float) i)) {
+            if (flag) {
                 return;
             }
 
             if (entity instanceof LivingEntity) {
-                LivingEntity livingEntity = (LivingEntity)entity;
+                LivingEntity entityliving = (LivingEntity) entity;
+
                 if (!this.level.isClientSide && this.getPierceLevel() <= 0) {
-                    livingEntity.setArrowCount(livingEntity.getArrowCount() + 1);
+                    entityliving.setArrowCount(entityliving.getArrowCount() + 1);
                 }
 
                 if (this.knockback > 0) {
-                    double d = Math.max(0.0D, 1.0D - livingEntity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
-                    Vec3 vec3 = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale((double)this.knockback * 0.6D * d);
-                    if (vec3.lengthSqr() > 0.0D) {
-                        livingEntity.push(vec3.x, 0.1D, vec3.z);
+                    double d0 = Math.max(0.0D, 1.0D - entityliving.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
+                    Vec3 vec3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale((double) this.knockback * 0.6D * d0);
+
+                    if (vec3d.lengthSqr() > 0.0D) {
+                        entityliving.push(vec3d.x, 0.1D, vec3d.z);
                     }
                 }
 
-                if (!this.level.isClientSide && entity2 instanceof LivingEntity) {
-                    EnchantmentHelper.doPostHurtEffects(livingEntity, entity2);
-                    EnchantmentHelper.doPostDamageEffects((LivingEntity)entity2, livingEntity);
+                if (!this.level.isClientSide && entity1 instanceof LivingEntity) {
+                    EnchantmentHelper.doPostHurtEffects(entityliving, entity1);
+                    EnchantmentHelper.doPostDamageEffects((LivingEntity) entity1, entityliving);
                 }
 
-                this.doPostHurtEffects(livingEntity);
-                if (entity2 != null && livingEntity != entity2 && livingEntity instanceof Player && entity2 instanceof ServerPlayer && !this.isSilent()) {
-                    ((ServerPlayer)entity2).connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.ARROW_HIT_PLAYER, 0.0F));
+                this.doPostHurtEffects(entityliving);
+                if (entity1 != null && entityliving != entity1 && entityliving instanceof Player && entity1 instanceof ServerPlayer && !this.isSilent()) {
+                    ((ServerPlayer) entity1).connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.ARROW_HIT_PLAYER, 0.0F));
                 }
 
                 if (!entity.isAlive() && this.piercedAndKilledEntities != null) {
-                    this.piercedAndKilledEntities.add(livingEntity);
+                    this.piercedAndKilledEntities.add(entityliving);
                 }
 
-                if (!this.level.isClientSide && entity2 instanceof ServerPlayer) {
-                    ServerPlayer serverPlayer = (ServerPlayer)entity2;
+                if (!this.level.isClientSide && entity1 instanceof ServerPlayer) {
+                    ServerPlayer entityplayer = (ServerPlayer) entity1;
+
                     if (this.piercedAndKilledEntities != null && this.shotFromCrossbow()) {
-                        CriteriaTriggers.KILLED_BY_CROSSBOW.trigger(serverPlayer, this.piercedAndKilledEntities);
+                        CriteriaTriggers.KILLED_BY_CROSSBOW.trigger(entityplayer, (Collection) this.piercedAndKilledEntities);
                     } else if (!entity.isAlive() && this.shotFromCrossbow()) {
-                        CriteriaTriggers.KILLED_BY_CROSSBOW.trigger(serverPlayer, Arrays.asList(entity));
+                        CriteriaTriggers.KILLED_BY_CROSSBOW.trigger(entityplayer, (Collection) Arrays.asList(entity));
                     }
                 }
             }
@@ -380,7 +460,7 @@
                 this.discard();
             }
         } else {
-            entity.setRemainingFireTicks(j);
+            entity.setRemainingFireTicks(k);
             this.setDeltaMovement(this.getDeltaMovement().scale(-0.1D));
             this.setYRot(this.getYRot() + 180.0F);
             this.yRotO += 180.0F;
@@ -399,15 +479,17 @@
     protected void onHitBlock(BlockHitResult blockHitResult) {
         this.lastState = this.level.getBlockState(blockHitResult.getBlockPos());
         super.onHitBlock(blockHitResult);
-        Vec3 vec3 = blockHitResult.getLocation().subtract(this.getX(), this.getY(), this.getZ());
-        this.setDeltaMovement(vec3);
-        Vec3 vec32 = vec3.normalize().scale((double)0.05F);
-        this.setPosRaw(this.getX() - vec32.x, this.getY() - vec32.y, this.getZ() - vec32.z);
+        Vec3 vec3d = blockHitResult.getLocation().subtract(this.getX(), this.getY(), this.getZ());
+
+        this.setDeltaMovement(vec3d);
+        Vec3 vec3d1 = vec3d.normalize().scale(0.05000000074505806D);
+
+        this.setPosRaw(this.getX() - vec3d1.x, this.getY() - vec3d1.y, this.getZ() - vec3d1.z);
         this.playSound(this.getHitGroundSoundEvent(), 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F));
         this.inGround = true;
         this.shakeTime = 7;
         this.setCritArrow(false);
-        this.setPierceLevel((byte)0);
+        this.setPierceLevel((byte) 0);
         this.setSoundEvent(SoundEvents.ARROW_HIT);
         this.setShotFromCrossbow(false);
         this.resetPiercedEntities();
@@ -421,8 +503,7 @@
         return this.soundEvent;
     }
 
-    protected void doPostHurtEffects(LivingEntity target) {
-    }
+    protected void doPostHurtEffects(LivingEntity target) {}
 
     @Nullable
     protected EntityHitResult findHitEntity(Vec3 currentPosition, Vec3 nextPosition) {
@@ -437,14 +518,14 @@
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
-        nbt.putShort("life", (short)this.life);
+        nbt.putShort("life", (short) this.life);
         if (this.lastState != null) {
             nbt.put("inBlockState", NbtUtils.writeBlockState(this.lastState));
         }
 
-        nbt.putByte("shake", (byte)this.shakeTime);
+        nbt.putByte("shake", (byte) this.shakeTime);
         nbt.putBoolean("inGround", this.inGround);
-        nbt.putByte("pickup", (byte)this.pickup.ordinal());
+        nbt.putByte("pickup", (byte) this.pickup.ordinal());
         nbt.putDouble("damage", this.baseDamage);
         nbt.putBoolean("crit", this.isCritArrow());
         nbt.putByte("PierceLevel", this.getPierceLevel());
@@ -470,7 +551,7 @@
         this.setCritArrow(nbt.getBoolean("crit"));
         this.setPierceLevel(nbt.getByte("PierceLevel"));
         if (nbt.contains("SoundEvent", 8)) {
-            this.soundEvent = Registry.SOUND_EVENT.getOptional(new ResourceLocation(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent());
+            this.soundEvent = (SoundEvent) Registry.SOUND_EVENT.getOptional(new ResourceLocation(nbt.getString("SoundEvent"))).orElse(this.getDefaultHitGroundSoundEvent());
         }
 
         this.setShotFromCrossbow(nbt.getBoolean("ShotFromCrossbow"));
@@ -480,7 +561,7 @@
     public void setOwner(@Nullable Entity entity) {
         super.setOwner(entity);
         if (entity instanceof Player) {
-            this.pickup = ((Player)entity).getAbilities().instabuild ? AbstractArrow.Pickup.CREATIVE_ONLY : AbstractArrow.Pickup.ALLOWED;
+            this.pickup = ((Player) entity).getAbilities().instabuild ? AbstractArrow.Pickup.CREATIVE_ONLY : AbstractArrow.Pickup.ALLOWED;
         }
 
     }
@@ -488,7 +569,22 @@
     @Override
     public void playerTouch(Player player) {
         if (!this.level.isClientSide && (this.inGround || this.isNoPhysics()) && this.shakeTime <= 0) {
-            if (this.tryPickup(player)) {
+            // CraftBukkit start
+            ItemStack itemstack = this.getPickupItem();
+            if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && player.getInventory().canHold(itemstack) > 0) {
+                ItemEntity item = new ItemEntity(this.level, this.getX(), this.getY(), this.getZ(), itemstack);
+                PlayerPickupArrowEvent event = new PlayerPickupArrowEvent((org.bukkit.entity.Player) player.getBukkitEntity(), new org.bukkit.craftbukkit.v1_19_R1.entity.CraftItem(this.level.getCraftServer(), this, item), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity());
+                // event.setCancelled(!entityhuman.canPickUpLoot); TODO
+                this.level.getCraftServer().getPluginManager().callEvent(event);
+
+                if (event.isCancelled()) {
+                    return;
+                }
+                itemstack = item.getItem();
+            }
+
+            if ((this.pickup == AbstractArrow.Pickup.ALLOWED && player.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && player.getAbilities().instabuild)) {
+                // CraftBukkit end
                 player.take(this, 1);
                 this.discard();
             }
@@ -545,39 +641,43 @@
     }
 
     public void setPierceLevel(byte level) {
-        this.entityData.set(PIERCE_LEVEL, level);
+        this.entityData.set(AbstractArrow.PIERCE_LEVEL, level);
     }
 
     private void setFlag(int index, boolean flag) {
-        byte b = this.entityData.get(ID_FLAGS);
+        byte b0 = (Byte) this.entityData.get(AbstractArrow.ID_FLAGS);
+
         if (flag) {
-            this.entityData.set(ID_FLAGS, (byte)(b | index));
+            this.entityData.set(AbstractArrow.ID_FLAGS, (byte) (b0 | index));
         } else {
-            this.entityData.set(ID_FLAGS, (byte)(b & ~index));
+            this.entityData.set(AbstractArrow.ID_FLAGS, (byte) (b0 & ~index));
         }
 
     }
 
     public boolean isCritArrow() {
-        byte b = this.entityData.get(ID_FLAGS);
-        return (b & 1) != 0;
+        byte b0 = (Byte) this.entityData.get(AbstractArrow.ID_FLAGS);
+
+        return (b0 & 1) != 0;
     }
 
     public boolean shotFromCrossbow() {
-        byte b = this.entityData.get(ID_FLAGS);
-        return (b & 4) != 0;
+        byte b0 = (Byte) this.entityData.get(AbstractArrow.ID_FLAGS);
+
+        return (b0 & 4) != 0;
     }
 
     public byte getPierceLevel() {
-        return this.entityData.get(PIERCE_LEVEL);
+        return (Byte) this.entityData.get(AbstractArrow.PIERCE_LEVEL);
     }
 
     public void setEnchantmentEffectsFromEntity(LivingEntity entity, float damageModifier) {
         int i = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER_ARROWS, entity);
         int j = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH_ARROWS, entity);
-        this.setBaseDamage((double)(damageModifier * 2.0F) + this.random.triangle((double)this.level.getDifficulty().getId() * 0.11D, 0.57425D));
+
+        this.setBaseDamage((double) (damageModifier * 2.0F) + this.random.triangle((double) this.level.getDifficulty().getId() * 0.11D, 0.57425D));
         if (i > 0) {
-            this.setBaseDamage(this.getBaseDamage() + (double)i * 0.5D + 0.5D);
+            this.setBaseDamage(this.getBaseDamage() + (double) i * 0.5D + 0.5D);
         }
 
         if (j > 0) {
@@ -600,11 +700,7 @@
     }
 
     public boolean isNoPhysics() {
-        if (!this.level.isClientSide) {
-            return this.noPhysics;
-        } else {
-            return (this.entityData.get(ID_FLAGS) & 2) != 0;
-        }
+        return !this.level.isClientSide ? this.noPhysics : ((Byte) this.entityData.get(AbstractArrow.ID_FLAGS) & 2) != 0;
     }
 
     public void setShotFromCrossbow(boolean shotFromCrossbow) {
@@ -612,9 +708,10 @@
     }
 
     public static enum Pickup {
-        DISALLOWED,
-        ALLOWED,
-        CREATIVE_ONLY;
+
+        DISALLOWED, ALLOWED, CREATIVE_ONLY;
+
+        private Pickup() {}
 
         public static AbstractArrow.Pickup byOrdinal(int ordinal) {
             if (ordinal < 0 || ordinal > values().length) {
