--- a/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -90,7 +_,14 @@
         ItemStack pickupItemStack,
         @Nullable ItemStack firedFromWeapon
     ) {
+        // CraftBukkit start - handle the owner before the rest of things
+        this(entityType, x, y, z, level, pickupItemStack, firedFromWeapon, null);
+    }
+
+    protected AbstractArrow(EntityType<? extends AbstractArrow> entityType, double x, double y, double z, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon, @Nullable LivingEntity ownerEntity) {
         this(entityType, level);
+        this.setOwner(ownerEntity);
+        // CraftBukkit end
         this.pickupItemStack = pickupItemStack.copy();
         this.applyComponentsFromItemStack(pickupItemStack);
         Unit unit = pickupItemStack.remove(DataComponents.INTANGIBLE_PROJECTILE);
@@ -115,8 +_,8 @@
     protected AbstractArrow(
         EntityType<? extends AbstractArrow> entityType, LivingEntity owner, Level level, ItemStack pickupItemStack, @Nullable ItemStack firedFromWeapon
     ) {
-        this(entityType, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon);
-        this.setOwner(owner);
+        this(entityType, owner.getX(), owner.getEyeY() - 0.1F, owner.getZ(), level, pickupItemStack, firedFromWeapon, owner); // CraftBukkit
+        // this.setOwner(owner); // SPIGOT-7744 - Moved to the above constructor
     }
 
     public void setSoundEvent(SoundEvent soundEvent) {
@@ -211,6 +_,7 @@
                 this.setSharedFlagOnFire(this.getRemainingFireTicks() > 0);
             }
         } else {
+            if (this.tickCount > 200) this.tickDespawn(); // Paper - tick life regardless after 10 seconds
             this.inGroundTime = 0;
             Vec3 vec31 = this.position();
             if (this.isInWater()) {
@@ -277,12 +_,12 @@
 
             if (entityHitResult == null) {
                 if (this.isAlive() && hitResult.getType() != HitResult.Type.MISS) {
-                    this.hitTargetOrDeflectSelf(hitResult);
+                    this.preHitTargetOrDeflectSelf(hitResult); // CraftBukkit - projectile hit event
                     this.hasImpulse = true;
                 }
                 break;
             } else if (this.isAlive() && !this.noPhysics) {
-                ProjectileDeflection projectileDeflection = this.hitTargetOrDeflectSelf(entityHitResult);
+                ProjectileDeflection projectileDeflection = this.preHitTargetOrDeflectSelf(entityHitResult); // CraftBukkit - projectile hit event
                 this.hasImpulse = true;
                 if (this.getPierceLevel() > 0 && projectileDeflection == ProjectileDeflection.NONE) {
                     continue;
@@ -315,13 +_,26 @@
         }
     }
 
+    // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows
+    @Override
+    public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult 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());
+        }
+        return super.preHitTargetOrDeflectSelf(hitResult);
+    }
+    // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows
+
     @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));
+        return this.isInGround() && this.level().noCollision(new AABB(this.position(), this.position()).inflate(0.06)); // Paper - getAttachedBlocks api; diff on change
     }
 
     private void startFalling() {
@@ -354,8 +_,8 @@
 
     protected void tickDespawn() {
         this.life++;
-        if (this.life >= 1200) {
-            this.discard();
+        if (this.life >= (this.pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (this.pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - Configurable non-player arrow despawn rate; TODO: Extract this to init?
+            this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
         }
     }
 
@@ -389,9 +_,9 @@
     }
 
     @Override
-    public void push(double x, double y, double z) {
+    public void push(double x, double y, double z, @Nullable Entity pushingEntity) { // Paper - add push source entity param
         if (!this.isInGround()) {
-            super.push(x, y, z);
+            super.push(x, y, z, pushingEntity); // Paper - add push source entity param
         }
     }
 
@@ -418,7 +_,7 @@
             }
 
             if (this.piercingIgnoreEntityIds.size() >= this.getPierceLevel() + 1) {
-                this.discard();
+                this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
                 return;
             }
 
@@ -434,10 +_,16 @@
             livingEntity.setLastHurtMob(entity);
         }
 
+        if (this.isCritArrow()) damageSource = damageSource.critical(); // Paper - add critical damage API
         boolean flag = entity.getType() == EntityType.ENDERMAN;
         int remainingFireTicks = entity.getRemainingFireTicks();
         if (this.isOnFire() && !flag) {
-            entity.igniteForSeconds(5.0F);
+            // CraftBukkit start
+            org.bukkit.event.entity.EntityCombustByEntityEvent combustEvent = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), entity.getBukkitEntity(), 5.0F);
+            if (combustEvent.callEvent()) {
+                entity.igniteForSeconds(combustEvent.getDuration(), false);
+            }
+            // CraftBukkit end
         }
 
         if (entity.hurtOrSimulate(damageSource, ceil)) {
@@ -475,7 +_,7 @@
 
             this.playSound(this.soundEvent, 1.0F, 1.2F / (this.random.nextFloat() * 0.2F + 0.9F));
             if (this.getPierceLevel() <= 0) {
-                this.discard();
+                this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
             }
         } else {
             entity.setRemainingFireTicks(remainingFireTicks);
@@ -486,7 +_,7 @@
                     this.spawnAtLocation(serverLevel2, this.getPickupItem(), 0.1F);
                 }
 
-                this.discard();
+                this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
             }
         }
     }
@@ -499,7 +_,7 @@
             double max = Math.max(0.0, 1.0 - entity.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
             Vec3 vec3 = this.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize().scale(d * 0.6 * max);
             if (vec3.lengthSqr() > 0.0) {
-                entity.push(vec3.x, 0.1, vec3.z);
+                entity.push(vec3.x, 0.1, vec3.z, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent
             }
         }
     }
@@ -605,7 +_,14 @@
 
     @Override
     public void setOwner(@Nullable Entity entity) {
+        // Paper start - Fix PickupStatus getting reset
+        this.setOwner(entity, true);
+    }
+
+    public void setOwner(@Nullable Entity entity, boolean resetPickup) {
+        // Paper end - Fix PickupStatus getting reset
         super.setOwner(entity);
+        if (!resetPickup) return; // Paper - Fix PickupStatus getting reset
 
         this.pickup = switch (entity) {
             case Player player when this.pickup == AbstractArrow.Pickup.DISALLOWED -> AbstractArrow.Pickup.ALLOWED;
@@ -617,9 +_,22 @@
     @Override
     public void playerTouch(Player entity) {
         if (!this.level().isClientSide && (this.isInGround() || this.isNoPhysics()) && this.shakeTime <= 0) {
-            if (this.tryPickup(entity)) {
+            // CraftBukkit start
+            ItemStack itemstack = this.getPickupItem();
+            if (this.pickup == Pickup.ALLOWED && !itemstack.isEmpty() && entity.getInventory().canHold(itemstack) > 0) {
+                net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemstack);
+                org.bukkit.event.player.PlayerPickupArrowEvent event = new org.bukkit.event.player.PlayerPickupArrowEvent((org.bukkit.entity.Player) entity.getBukkitEntity(), (org.bukkit.entity.Item) item.getBukkitEntity(), (org.bukkit.entity.AbstractArrow) this.getBukkitEntity());
+                // event.setCancelled(!entityhuman.canPickUpLoot); TODO
+                if (!event.callEvent()) {
+                    return;
+                }
+                itemstack = item.getItem();
+            }
+
+            if ((this.pickup == AbstractArrow.Pickup.ALLOWED && entity.getInventory().add(itemstack)) || (this.pickup == AbstractArrow.Pickup.CREATIVE_ONLY && entity.getAbilities().instabuild)) {
+                // CraftBukkit end
                 entity.take(this, 1);
-                this.discard();
+                this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
             }
         }
     }
