From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: jmp <jasonpenilla2@me.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/EntityArrow.java b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java
index e440d26c920c4efddf958c61bfdfa508273062cc..3ee404effe339a5742926255da6a9c41d1bc9367 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityArrow.java
@@ -61,7 +61,7 @@ public abstract class EntityArrow extends IProjectile {
     protected int c;
     public EntityArrow.PickupStatus fromPlayer;
     public int shake;
-    public int despawnCounter;
+    //public int despawnCounter; // Purpur - moved to IProjectile
     private double damage;
     public int knockbackStrength;
     private SoundEffect ak;
@@ -295,13 +295,23 @@ public abstract class EntityArrow extends IProjectile {
 
     }
 
-    protected final void tickDespawnCounter() { this.h(); } // Paper - OBFHELPER
-    protected void h() {
-        ++this.despawnCounter;
-        if (this.despawnCounter >= (fromPlayer == PickupStatus.CREATIVE_ONLY ? world.paperConfig.creativeArrowDespawnRate : (fromPlayer == PickupStatus.DISALLOWED ? world.paperConfig.nonPlayerArrowDespawnRate : ((this instanceof EntityThrownTrident) ? world.spigotConfig.tridentDespawnRate : world.spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
-            this.die();
+    // Purpur start
+    protected int getPurpurDespawnRate() {
+        if (fromPlayer == PickupStatus.CREATIVE_ONLY) {
+            return world.paperConfig.creativeArrowDespawnRate;
+        }
+        if (fromPlayer == PickupStatus.DISALLOWED) {
+            return world.paperConfig.nonPlayerArrowDespawnRate;
+        }
+        if (this instanceof EntityThrownTrident) {
+            return world.spigotConfig.tridentDespawnRate;
         }
+        return world.spigotConfig.arrowDespawnRate;
+    }
+    // Purpur end
 
+    protected void h() {
+        tickDespawnCounter(); // Purpur
     }
 
     private void A() {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java
index 27853f510e15e40c66da2cb4905c43f5e8f99d3d..98dcfedc8826ebb067438be713549e2cfb19ebb0 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityDragonFireball.java
@@ -87,4 +87,11 @@ public class EntityDragonFireball extends EntityFireball {
     protected boolean W_() {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.dragonFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java b/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java
index dc2e51718395494f60b0376d65d496daf2f76e71..d97511c27ff376b2dd0fbedb227f9a0c337a1264 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityEgg.java
@@ -99,4 +99,11 @@ public class EntityEgg extends EntityProjectileThrowable {
     protected Item getDefaultItem() {
         return Items.EGG;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.eggDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java
index efdf5bc4f07231690c680429b3f77bd07970eee0..cf2c691357c41a7e7044f7a719144db2ffab5dbe 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityEnderPearl.java
@@ -122,4 +122,11 @@ public class EntityEnderPearl extends EntityProjectileThrowable {
 
         return super.b(worldserver);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.enderPearlDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java b/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java
index f9a355c847d778a9aad1987882fc816af92450ba..9b4b8b1a0f7654c9c30ca614cac6f485f82db5ef 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityFireworks.java
@@ -325,4 +325,11 @@ public class EntityFireworks extends IProjectile {
     public Packet<?> P() {
         return new PacketPlayOutSpawnEntity(this);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.fireworkDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java
index dc6d279766ccc83a8f450028a09491b1c88f524c..5a5773209183331d849368c6b300367ac0ebe203 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityFishingHook.java
@@ -617,4 +617,11 @@ public class EntityFishingHook extends IProjectile {
 
         private HookState() {}
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.fishingHookDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java
index cf2663d9883654f53b327246d85ee63c3990cd71..e860737bacfea0a1d728dbaaf41d62165658ad89 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLargeFireball.java
@@ -77,4 +77,11 @@ public class EntityLargeFireball extends EntityFireballFireball {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.largeFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java
index 8aef834a6e8fcf5d44986745affb8f27bc3dfd6b..0bfb80331cea6bd2cf85a9475b6416691edd8b0b 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityLlamaSpit.java
@@ -88,4 +88,11 @@ public class EntityLlamaSpit extends IProjectile {
     public Packet<?> P() {
         return new PacketPlayOutSpawnEntity(this);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.llamaSpitDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java b/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java
index dbc0afc5fb9e358a3e6d596692f57fb28303c4da..a3344719bcf178df5b63cda6f6a854c2df174fa5 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityPotion.java
@@ -270,4 +270,11 @@ public class EntityPotion extends EntityProjectileThrowable {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.potionDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java b/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java
index 1ae528ccd09a6536b3aac320e6218f03c274d6a9..cfc1376bfed9399daa6f27f54780ccf8e05753c6 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityShulkerBullet.java
@@ -337,4 +337,11 @@ public class EntityShulkerBullet extends IProjectile {
     public Packet<?> P() {
         return new PacketPlayOutSpawnEntity(this);
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.shulkerBulletDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java
index d139c5806e5971e82865c2ce627e87c631e42d7a..bf747cbf6e1ef9ea9d1d41d0441b29a46ce874c0 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySmallFireball.java
@@ -100,4 +100,11 @@ public class EntitySmallFireball extends EntityFireballFireball {
     public boolean damageEntity(DamageSource damagesource, float f) {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.smallFireballDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java
index 3ec380ec35fade3bcc61c5f45cee651eb45ae073..0d3b9c81e47eef645335e49a1d6d88db7338aa4b 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntitySnowball.java
@@ -25,6 +25,12 @@ public class EntitySnowball extends EntityProjectileThrowable {
         super(EntityTypes.SNOWBALL, d0, d1, d2, world);
     }
 
+    // Purpur start
+    protected int getPurpurDespawnRate() {
+        return world.purpurConfig.snowballDespawnRate;
+    }
+    // Purpur end
+
     @Override
     protected Item getDefaultItem() {
         return Items.SNOWBALL;
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java
index e07353a6b34196e3d275ba482fbef7e4d209c31d..6ef87bd6969603a51f09034ad87b89ab8a25eadb 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityThrownExpBottle.java
@@ -61,4 +61,11 @@ public class EntityThrownExpBottle extends EntityProjectileThrowable {
         }
 
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.expBottleDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java
index 021a7e31dc3650c0c404a893374528e6a63dfbad..2fe0e32a1158cccb3060f5a986c9fc41a0237aa8 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/EntityWitherSkull.java
@@ -137,4 +137,11 @@ public class EntityWitherSkull extends EntityFireball {
     protected boolean W_() {
         return false;
     }
+
+    // Purpur start
+    @Override
+    protected int getPurpurDespawnRate() {
+        return this.world.purpurConfig.witherSkullDespawnRate;
+    }
+    // Purpur end
 }
diff --git a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java
index 3914081629669aea19d50530db996728bbfa607f..62fa5be9090c8789e91bf9b9f614e74a4a6babdd 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/IProjectile.java
@@ -25,11 +25,25 @@ public abstract class IProjectile extends Entity {
     private UUID shooter;
     private int c;
     private boolean d; public boolean leftOwner() { return d; } public void setLeftOwner(boolean leftOwner) { this.d = leftOwner; } // Purpur - OBFHELPER
+    public int despawnCounter; // Purpur - moved from EntityArrow
 
     IProjectile(EntityTypes<? extends IProjectile> entitytypes, World world) {
         super(entitytypes, world);
     }
 
+    // Purpur start
+    protected final void tickDespawnCounter() {
+        if (this.getPurpurDespawnRate() != -1) {
+            ++this.despawnCounter;
+            if (this.despawnCounter >= this.getPurpurDespawnRate()) {
+                this.die();
+            }
+        }
+    }
+
+    protected abstract int getPurpurDespawnRate();
+    // Purpur end
+
     public void setShooter(@Nullable Entity entity) {
         if (entity != null) {
             this.shooter = entity.getUniqueID();
@@ -84,6 +98,12 @@ public abstract class IProjectile extends Entity {
         }
 
         super.tick();
+
+        // Purpur start
+        if (!(this instanceof EntityArrow)) { // EntityArrow handles its own despawn counter
+            this.tickDespawnCounter();
+        }
+        // Purpur end
     }
 
     public boolean checkIfLeftOwner() { return this.h(); } // Purpur - OBFHELPER
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
index 847975c3c2309633e1505b9ee37d9d7ba9019f0f..4015a27eebbfd655d3723813a0632f3183d48af7 100644
--- a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -165,6 +165,35 @@ public class PurpurWorldConfig {
         idleTimeoutUpdateTabList = getBoolean("gameplay-mechanics.player.idle-timeout.update-tab-list", idleTimeoutUpdateTabList);
     }
 
+    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 useBetterMending = false;
     public boolean boatEjectPlayersOnLand = false;
     public boolean disableDropsOnCrammingDeath = false;
