From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 14 Sep 2020 10:09:05 -0700
Subject: [PATCH] Despawn rate config options per projectile type

Default values of -1 respect vanilla behaviour.

diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
index 6636845ea044c3810e1880aad8b679134cd33668..f6fc98ffe49d5af9a69f57f2e53e6010f71d55d9 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -62,7 +62,7 @@ public abstract class AbstractArrow extends Projectile {
     protected int inGroundTime;
     public AbstractArrow.Pickup pickup;
     public int shakeTime;
-    public int life;
+    // public int life; // Purpur - moved to Projectile
     private double baseDamage;
     public int knockback;
     private SoundEvent soundEvent;
@@ -320,12 +320,23 @@ public abstract class AbstractArrow extends Projectile {
 
     }
 
-    protected void tickDespawn() {
-        ++this.life;
-        if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? level.paperConfig.creativeArrowDespawnRate : (pickup == Pickup.DISALLOWED ? level.paperConfig.nonPlayerArrowDespawnRate : ((this instanceof ThrownTrident) ? level.spigotConfig.tridentDespawnRate : level.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
-            this.discard();
+    // Purpur start
+    protected int getPurpurDespawnRate() {
+        if (pickup == Pickup.CREATIVE_ONLY) {
+            return level.paperConfig.creativeArrowDespawnRate;
+        }
+        if (pickup == Pickup.DISALLOWED) {
+            return level.paperConfig.nonPlayerArrowDespawnRate;
+        }
+        if (this instanceof ThrownTrident) {
+            return level.spigotConfig.tridentDespawnRate;
         }
+        return level.spigotConfig.arrowDespawnRate;
+    }
+    // Purpur end
 
+    protected void tickDespawn() {
+        tickDespawnCounter(); // Purpur
     }
 
     private void resetPiercedEntities() {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java b/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
index 6afe37e42d88701af38df5793a9ea9d7d2cda5c5..1de27407c92d496715899fcafb3794df9f5ef6cd 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/DragonFireball.java
@@ -81,4 +81,11 @@ public class DragonFireball extends AbstractHurtingProjectile {
     protected boolean shouldBurn() {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.dragonFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
index 3ac0d0419cbdacabf647a530a82ddf67ddaa13b7..78111e7c26f5237e9954791cf17037eb6fd111b2 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
@@ -355,4 +355,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
     public boolean isAttackable() {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.fireworkDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 852a4edde291bf368b2396e3c94ab402e3c66622..83b733efa3a4e135870806589ca9733ca6d8775b 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -664,4 +664,11 @@ public class FishingHook extends Projectile {
 
         private OpenWaterType() {}
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.fishingHookDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
index 5237b699e000b4fed99be39b0a7e2daab9c8bf42..e69213b43c8aa5a7c04add7a87482d531fbf52d2 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/LargeFireball.java
@@ -77,4 +77,11 @@ public class LargeFireball extends Fireball {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.largeFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
index f1a12b147d55e34d4f8374593640a311598cf1a6..c4bdebd4310035a5cce5a5790f538eb0b8021b30 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java
@@ -100,4 +100,11 @@ public class LlamaSpit extends Projectile {
 
         this.setDeltaMovement(d0, d1, d2);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.llamaSpitDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 0837875231ef96ff58f2fee3e558d7066d613cb8..0079464e934f495f55a4e7edbe7031ec13e4d8d4 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -33,6 +33,7 @@ public abstract class Projectile extends Entity {
     private Entity cachedOwner;
     private boolean leftOwner;
     private boolean hasBeenShot;
+    public int life; // Purpur - moved from AbstractArrow
 
     // CraftBukkit start
     public boolean hitCancelled = false; // Purpur - private -> public
@@ -72,6 +73,19 @@ public abstract class Projectile extends Entity {
     }
     // Airplane start
 
+    // Purpur start
+    protected final void tickDespawnCounter() {
+        if (this.getPurpurDespawnRate() != -1) {
+            ++this.life;
+            if (this.life >= this.getPurpurDespawnRate()) {
+                this.discard();
+            }
+        }
+    }
+
+    protected abstract int getPurpurDespawnRate();
+    // Purpur end
+
     public void setOwner(@Nullable Entity entity) {
         if (entity != null) {
             this.ownerUUID = entity.getUUID();
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ShulkerBullet.java b/src/main/java/net/minecraft/world/entity/projectile/ShulkerBullet.java
index 123f9a93b014107c8f609d38a2b8d37261bb5d18..aa91cc06f6411fe83467e43c0df1145cb85aead0 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ShulkerBullet.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ShulkerBullet.java
@@ -63,6 +63,13 @@ public class ShulkerBullet extends Projectile {
         projectileSource = (org.bukkit.entity.LivingEntity) owner.getBukkitEntity(); // CraftBukkit
     }
 
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.shulkerBulletDespawnRate;
+    }
+    // Purpur end
+
     // CraftBukkit start
     public Entity getTarget() {
         return this.finalTarget;
diff --git a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
index b77d04ef22711a4f90e274e81faa261f3f6c25af..a6d75f20d6b7679d53c3c081c6632e9c303e2d74 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java
@@ -99,4 +99,11 @@ public class SmallFireball extends Fireball {
     public boolean hurt(DamageSource source, float amount) {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.smallFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
index a725851060f13e734dbd2fbf8c83c9e1af57a8b7..ed2f039c4042861bcfa2e41d8281eefd37daa9fa 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Snowball.java
@@ -67,4 +67,11 @@ public class Snowball extends ThrowableItemProjectile {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.snowballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
index 77941e3981e49cf5662b3e3c86a9c419080b17c8..8c6243aab556c993b43ab52e216bcb0a70d1a686 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
@@ -107,4 +107,11 @@ public class ThrownEgg extends ThrowableItemProjectile {
     protected Item getDefaultItem() {
         return Items.EGG;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.eggDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
index 541ca82405d0b4d1457dcd63b58dc61eb67482d6..a65e0a3357a27dfdf62ba45ebfeb531958851285 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
@@ -121,4 +121,11 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
 
         return super.changeDimension(destination);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.enderPearlDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
index 11d1db5ef709dfb6fa596ebc4f5fff1415ad4f6d..ef771a190c6a437d4cf741a6d5a3be88070e011d 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
@@ -56,4 +56,11 @@ public class ThrownExperienceBottle extends ThrowableItemProjectile {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.expBottleDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
index 8676796ff65cd0bd3f215dc7edcf3a5b2291ca27..15e7c19093e74a3354a115074449c1f6a830afc9 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
@@ -303,4 +303,11 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.potionDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
index 4a11f7417b438ee5711a720aca3321c88e970b2a..46b74271ce5f614f07754db14d2a552c36f73226 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/WitherSkull.java
@@ -136,4 +136,11 @@ public class WitherSkull extends AbstractHurtingProjectile {
     protected boolean shouldBurn() {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.level.purpurConfig.witherSkullDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index ef39747d7fea72a460aea674fbb10a602bbc8152..aa4a3e84b3920676e1bdcfe3d12d7f77ea0868cf 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -267,6 +267,35 @@ public class PurpurWorldConfig {
         totemOfUndyingWorksInInventory = getBoolean("gameplay-mechanics.player.totem-of-undying-works-in-inventory", totemOfUndyingWorksInInventory);
     }
 
+    public int dragonFireballDespawnRate = -1;
+    public int eggDespawnRate = -1;
+    public int enderPearlDespawnRate = -1;
+    public int expBottleDespawnRate = -1;
+    public int fireworkDespawnRate = -1;
+    public int fishingHookDespawnRate = -1;
+    public int largeFireballDespawnRate = -1;
+    public int llamaSpitDespawnRate = -1;
+    public int potionDespawnRate = -1;
+    public int shulkerBulletDespawnRate = -1;
+    public int smallFireballDespawnRate = -1;
+    public int snowballDespawnRate = -1;
+    public int witherSkullDespawnRate = -1;
+    private void projectileDespawnRateSettings() {
+        dragonFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.dragon_fireball", dragonFireballDespawnRate);
+        eggDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.egg", eggDespawnRate);
+        enderPearlDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.ender_pearl", enderPearlDespawnRate);
+        expBottleDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.experience_bottle", expBottleDespawnRate);
+        fireworkDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.firework_rocket", fireworkDespawnRate);
+        fishingHookDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.fishing_bobber", fishingHookDespawnRate);
+        largeFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.fireball", largeFireballDespawnRate);
+        llamaSpitDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.llama_spit", llamaSpitDespawnRate);
+        potionDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.potion", potionDespawnRate);
+        shulkerBulletDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.shulker_bullet", shulkerBulletDespawnRate);
+        smallFireballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.small_fireball", smallFireballDespawnRate);
+        snowballDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.snowball", snowballDespawnRate);
+        witherSkullDespawnRate = getInt("gameplay-mechanics.projectile-despawn-rates.wither_skull", witherSkullDespawnRate);
+    }
+
     public boolean silkTouchEnabled = false;
     public String silkTouchSpawnerName = "Spawner";
     public List<String> silkTouchSpawnerLore = new ArrayList<>();
