--- a/net/minecraft/world/entity/projectile/EntityShulkerBullet.java
+++ b/net/minecraft/world/entity/projectile/EntityShulkerBullet.java
@@ -32,6 +32,10 @@
 import net.minecraft.world.phys.MovingObjectPositionEntity;
 import net.minecraft.world.phys.Vec3D;
 
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
+
 public class EntityShulkerBullet extends IProjectile {
 
     private static final double SPEED = 0.15D;
@@ -60,8 +64,21 @@
         this.finalTarget = entity;
         this.currentMoveDirection = EnumDirection.UP;
         this.selectNextMoveDirection(enumdirection_enumaxis);
+        projectileSource = (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity(); // CraftBukkit
+    }
+
+    // CraftBukkit start
+    public Entity getTarget() {
+        return this.finalTarget;
     }
 
+    public void setTarget(Entity e) {
+        this.finalTarget = e;
+        this.currentMoveDirection = EnumDirection.UP;
+        this.selectNextMoveDirection(EnumDirection.EnumAxis.X);
+    }
+    // CraftBukkit end
+
     @Override
     public SoundCategory getSoundSource() {
         return SoundCategory.HOSTILE;
@@ -194,7 +211,7 @@
     @Override
     public void checkDespawn() {
         if (this.level().getDifficulty() == EnumDifficulty.PEACEFUL) {
-            this.discard();
+            this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
         }
 
     }
@@ -239,7 +256,7 @@
         }
 
         if (movingobjectposition != null && this.isAlive() && movingobjectposition.getType() != MovingObjectPosition.EnumMovingObjectType.MISS) {
-            this.hitTargetOrDeflectSelf(movingobjectposition);
+            this.preHitTargetOrDeflectSelf(movingobjectposition); // CraftBukkit - projectile hit event
         }
 
         ProjectileHelper.rotateTowardsMovement(this, 0.5F);
@@ -312,7 +329,7 @@
             if (entity instanceof EntityLiving) {
                 EntityLiving entityliving1 = (EntityLiving) entity;
 
-                entityliving1.addEffect(new MobEffect(MobEffects.LEVITATION, 200), (Entity) MoreObjects.firstNonNull(entity1, this));
+                entityliving1.addEffect(new MobEffect(MobEffects.LEVITATION, 200), (Entity) MoreObjects.firstNonNull(entity1, this), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
             }
         }
 
@@ -326,14 +343,20 @@
     }
 
     private void destroy() {
-        this.discard();
+        // CraftBukkit start - add Bukkit remove cause
+        this.destroy(null);
+    }
+
+    private void destroy(EntityRemoveEvent.Cause cause) {
+        this.discard(cause);
+        // CraftBukkit end
         this.level().gameEvent((Holder) GameEvent.ENTITY_DAMAGE, this.position(), GameEvent.a.of((Entity) this));
     }
 
     @Override
     protected void onHit(MovingObjectPosition movingobjectposition) {
         super.onHit(movingobjectposition);
-        this.destroy();
+        this.destroy(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
     }
 
     @Override
@@ -348,9 +371,14 @@
 
     @Override
     public boolean hurtServer(WorldServer worldserver, DamageSource damagesource, float f) {
+        // CraftBukkit start
+        if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f, false)) {
+            return false;
+        }
+        // CraftBukkit end
         this.playSound(SoundEffects.SHULKER_BULLET_HURT, 1.0F, 1.0F);
         worldserver.sendParticles(Particles.CRIT, this.getX(), this.getY(), this.getZ(), 15, 0.2D, 0.2D, 0.2D, 0.0D);
-        this.destroy();
+        this.destroy(EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause
         return true;
     }
 
