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/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java
index f983516b89cdf7ce7fdea8f5a5b1a29dd01ae597..74529a297540ea9c69952d88fe3bb5a13816dcef 100644
--- a/src/main/java/net/minecraft/server/EntityArrow.java
+++ b/src/main/java/net/minecraft/server/EntityArrow.java
@@ -23,7 +23,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;
@@ -257,13 +257,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/server/EntityDragonFireball.java b/src/main/java/net/minecraft/server/EntityDragonFireball.java
index 27032abad4f3da1d1b28a3cec49e3fc079deadb9..9d2d5be5eedc60749e276434be9be6ab41f2289d 100644
--- a/src/main/java/net/minecraft/server/EntityDragonFireball.java
+++ b/src/main/java/net/minecraft/server/EntityDragonFireball.java
@@ -75,4 +75,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/server/EntityEgg.java b/src/main/java/net/minecraft/server/EntityEgg.java
index edce89169b3ca2894852087b83a6bf035ba43c3f..4951abdfa13d170b7075a0223dd0096d77dec6ea 100644
--- a/src/main/java/net/minecraft/server/EntityEgg.java
+++ b/src/main/java/net/minecraft/server/EntityEgg.java
@@ -87,4 +87,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/server/EntityEnderPearl.java b/src/main/java/net/minecraft/server/EntityEnderPearl.java
index e42dd066e76a3d2bc3270774f48bb8c8fd47cc38..44dbe818b19c927098c1e6b2bcb556378be5637c 100644
--- a/src/main/java/net/minecraft/server/EntityEnderPearl.java
+++ b/src/main/java/net/minecraft/server/EntityEnderPearl.java
@@ -107,4 +107,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/server/EntityFireworks.java b/src/main/java/net/minecraft/server/EntityFireworks.java
index d8faa18724baa240fca78a35c362cf661615ec4d..e4c2bf2de6c032332b7557c240bb458297bdd33f 100644
--- a/src/main/java/net/minecraft/server/EntityFireworks.java
+++ b/src/main/java/net/minecraft/server/EntityFireworks.java
@@ -301,4 +301,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/server/EntityFishingHook.java b/src/main/java/net/minecraft/server/EntityFishingHook.java
index 9841c7c27cd296a5156ba79ab734d45922bacaf7..f0502c7f5419f637641b48d8c87f5df206e4f922 100644
--- a/src/main/java/net/minecraft/server/EntityFishingHook.java
+++ b/src/main/java/net/minecraft/server/EntityFishingHook.java
@@ -579,4 +579,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/server/EntityLargeFireball.java b/src/main/java/net/minecraft/server/EntityLargeFireball.java
index b4b0dfbc70f91f74f9792b835ec2f8d5af41c311..d12de20cf4bb2345c616d3cc0b9f50bddb5135ee 100644
--- a/src/main/java/net/minecraft/server/EntityLargeFireball.java
+++ b/src/main/java/net/minecraft/server/EntityLargeFireball.java
@@ -66,4 +66,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/server/EntityLlamaSpit.java b/src/main/java/net/minecraft/server/EntityLlamaSpit.java
index 480a02a8f6ec7110f9af8f2037fdc09a7a54ef01..aa9afb60808a9988b38cf588ec9f649ee09c728e 100644
--- a/src/main/java/net/minecraft/server/EntityLlamaSpit.java
+++ b/src/main/java/net/minecraft/server/EntityLlamaSpit.java
@@ -73,4 +73,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/server/EntityPotion.java b/src/main/java/net/minecraft/server/EntityPotion.java
index b338cb771aa8ba7a810b8129ca04640d115b68ba..dfc0538cc8cb8015fe79978ee360c86127118330 100644
--- a/src/main/java/net/minecraft/server/EntityPotion.java
+++ b/src/main/java/net/minecraft/server/EntityPotion.java
@@ -241,4 +241,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/server/EntityShulkerBullet.java b/src/main/java/net/minecraft/server/EntityShulkerBullet.java
index a4d94385ede0303417d676155c2c0b226681cc59..da38bdd6055d06005cfee3e73c32230ad7b480ff 100644
--- a/src/main/java/net/minecraft/server/EntityShulkerBullet.java
+++ b/src/main/java/net/minecraft/server/EntityShulkerBullet.java
@@ -313,4 +313,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/server/EntitySmallFireball.java b/src/main/java/net/minecraft/server/EntitySmallFireball.java
index 350e92ac99fe48ba046a51e1db4b977dd9bfc20a..4ed7a20bfed267776628457a4b33178bac7d1972 100644
--- a/src/main/java/net/minecraft/server/EntitySmallFireball.java
+++ b/src/main/java/net/minecraft/server/EntitySmallFireball.java
@@ -86,4 +86,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/server/EntitySnowball.java b/src/main/java/net/minecraft/server/EntitySnowball.java
index e44249f59b742d16f08643ee2a83fdcd0bed9590..34a5f481e6ed1357861dca15fb4013ec8484a292 100644
--- a/src/main/java/net/minecraft/server/EntitySnowball.java
+++ b/src/main/java/net/minecraft/server/EntitySnowball.java
@@ -14,6 +14,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/server/EntityThrownExpBottle.java b/src/main/java/net/minecraft/server/EntityThrownExpBottle.java
index 2d3ca8c424f2088027d51066d634c48723e96214..1d32518bd7982f20574d56f2f2ea4142ea1e015d 100644
--- a/src/main/java/net/minecraft/server/EntityThrownExpBottle.java
+++ b/src/main/java/net/minecraft/server/EntityThrownExpBottle.java
@@ -51,4 +51,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/server/EntityWitherSkull.java b/src/main/java/net/minecraft/server/EntityWitherSkull.java
index 2c02e114cce1f49b643e75e7ab3c05be716d7dba..4a97a7517dc1a2a25c578d9e168240cc19ab0831 100644
--- a/src/main/java/net/minecraft/server/EntityWitherSkull.java
+++ b/src/main/java/net/minecraft/server/EntityWitherSkull.java
@@ -116,4 +116,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/server/IProjectile.java b/src/main/java/net/minecraft/server/IProjectile.java
index b7e540dfeeabb13227596ecfc6eddabf3cfde537..56adefabdfbf444e87129715f107c6d3aafe4ca7 100644
--- a/src/main/java/net/minecraft/server/IProjectile.java
+++ b/src/main/java/net/minecraft/server/IProjectile.java
@@ -13,11 +13,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();
@@ -72,6 +86,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 1c9db2dc3d5577906aa1ac208aad3c6865040381..c9884c382e3e16db0d4c1b7d0d804aafbd6a3fa8 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;
