diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
index bd5d46a11..c394a3896 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererArrow.java
@@ -11,6 +11,13 @@ public class EntityRendererArrow extends EntityRenderer<ProjectileArrow> {
     @Override
     public void render(@NotNull TessellatorGeneral tessellator, @NotNull ProjectileArrow arrow, double x, double y, double z,
                        float yaw, float partialTick) {
+        int prime = ((ProjectileArrow.LIFETIME * 3)/4);
+        if ((arrow.ticksInGround + partialTick) > prime) {
+            int pastPrime = arrow.ticksInGround - prime;
+            double toDeath = 1 - ((pastPrime + partialTick) * 4d)/ProjectileArrow.LIFETIME; // progress of age from 75% of lifetime to 100%
+            if (java.lang.Math.cos(((pastPrime + partialTick) * java.lang.Math.PI)/ (2.5 + 5.5 * toDeath)) > 0) return;
+        }
+
         bindTexture("/assets/minecraft/textures/entity/arrows.png");
         GLRenderer.pushFrame();
         GLRenderer.modelM4f().translate((float) x, (float) y, (float) z);
diff --git a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
index f548ab5cb..62cdf9781 100644
--- a/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
+++ b/game/client/src/main/java/net/minecraft/client/render/entity/EntityRendererItem.java
@@ -18,6 +18,12 @@ public class EntityRendererItem extends EntityRenderer<EntityItem> {
     }
 
     public void render(@NotNull TessellatorGeneral tessellator, final @NotNull EntityItem entity, final double x, final double y, final double z, final float yaw, final float partialTick) {
+        int prime = ((entity.lifetime * 3)/4);
+        if (entity.lifetime >= 0 && (entity.age + partialTick) > prime) {
+            int pastPrime = entity.age - prime;
+            double toDeath = 1 - ((pastPrime + partialTick) * 4d)/entity.lifetime; // progress of age from 75% of lifetime to 100%
+            if (Math.cos(((pastPrime + partialTick) * Math.PI)/ (2.5 + 5.5 * toDeath)) > 0) return;
+        }
         final ItemStack itemstack = entity.item;
         if (itemstack == null) {
             return;
diff --git a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java
index 2452bcfaf..5dda2658f 100644
--- a/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java
+++ b/game/core/src/main/java/net/minecraft/core/data/gamerule/GameRules.java
@@ -17,6 +17,8 @@ public abstract class GameRules
     public static GameRuleBoolean DO_FIRE_SPREAD = register(new GameRuleBoolean("doFireSpread", "gamerule.do_fire_spread", true));
     public static GameRuleBoolean INSTANT_HEALING = register(new GameRuleBoolean("instantHealing", "gamerule.instant_healing", false));
     public static GameRuleInteger RANDOM_TICK_SPEED = register(new GameRuleInteger("randomTickSpeed", "gamerule.random_tick_speed", 4));
+    public static GameRuleInteger ITEM_DESPAWN_DELAY = register(new GameRuleInteger("itemDespawnDelay", "gamerule.item_despawn_delay", 6000));
+    public static GameRuleInteger DROPPED_ITEM_DESPAWN_DELAY = register(new GameRuleInteger("droppedItemDespawnDelay", "gamerule.dropped_item_despawn_delay", 6000));
 
     public static <T extends GameRule<?>> T register(T gameRule)
     {
diff --git a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
index 6837107e2..ead3acd26 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/EntityItem.java
@@ -9,6 +9,7 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockLogicLog;
 import net.minecraft.core.block.Blocks;
 import net.minecraft.core.block.material.Materials;
+import net.minecraft.core.data.gamerule.GameRules;
 import net.minecraft.core.entity.player.Player;
 import net.minecraft.core.item.ItemDiscMusic;
 import net.minecraft.core.item.Items;
@@ -21,8 +22,8 @@ import org.joml.primitives.AABBd;
 
 public class EntityItem extends Entity
 {
-    private static final int LIFETIME = 6000;
     public ItemStack item;
+    public int lifetime;
     public int age;
     public int pickupDelay;
     private int health;
@@ -30,7 +31,7 @@ public class EntityItem extends Entity
     public int basketPickupDelay = 0;
     public static boolean enableItemClumping = true;
 
-    public EntityItem(World world, double x, double y, double z, ItemStack itemstack) {
+    public EntityItem(@NotNull World world, double x, double y, double z, @NotNull ItemStack itemstack) {
         super(world);
         this.age = 0;
         this.health = 8;
@@ -43,6 +44,7 @@ public class EntityItem extends Entity
         this.xd = (float)(Math.random() * 0.2D - 0.1D);
         this.yd = 0.2D;
         this.zd = (float)(Math.random() * 0.2D - 0.1D);
+        this.lifetime = world.getGameRuleValue(GameRules.ITEM_DESPAWN_DELAY);
         if(itemstack == null) {
         	System.err.println("Created EntityItem with no item!");
         	Thread.dumpStack();
@@ -141,7 +143,7 @@ public class EntityItem extends Entity
             this.yd *= -0.5D;
         }
         this.age++;
-        if(this.age >= LIFETIME)
+        if(this.age >= this.lifetime && this.lifetime >= 0) // Negative lifetime indicates items should last forever
         {
             remove();
         }
@@ -179,6 +181,7 @@ public class EntityItem extends Entity
         if(this.item != null) {
         	tag.putCompound("Item", this.item.writeToNBT(new CompoundTag()));
         }
+        tag.putInt("Lifetime", this.lifetime);
     }
 
     @Override
@@ -189,6 +192,7 @@ public class EntityItem extends Entity
         if(tag.containsKey("Item")) {
             this.item = ItemStack.readItemStackFromNbt(tag.getCompound("Item"));
         }
+        this.lifetime = tag.getIntegerOrDefault("Lifetime", this.world.getGameRuleValue(GameRules.ITEM_DESPAWN_DELAY));
     }
 
 	@Override
diff --git a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
index ebcec584e..7169b1449 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/player/Player.java
@@ -675,6 +675,7 @@ public abstract class Player
 
         final @NotNull EntityItem itemEntity = new EntityItem(this.world, this.x, (this.y - 0.3) + (double) this.getHeadHeight(), this.z, stack);
         itemEntity.pickupDelay = 40;
+        itemEntity.lifetime = this.world.getGameRuleValue(GameRules.DROPPED_ITEM_DESPAWN_DELAY);
 
         if (randomDirection) {
             final float speed = this.random.nextFloat() * 0.5F;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
index f3a3b729b..ee2bdf387 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/Projectile.java
@@ -19,8 +19,8 @@ import java.util.List;
 
 public class Projectile extends Entity {
     public Mob owner;
-    protected int ticksInGround;
-    protected int ticksInAir;
+    public int ticksInGround;
+    public int ticksInAir;
     public int damage;
     public Item modelItem = null;
     protected float defaultGravity;
diff --git a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
index 7d732e303..fac48adf6 100644
--- a/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
+++ b/game/core/src/main/java/net/minecraft/core/entity/projectile/ProjectileArrow.java
@@ -19,6 +19,7 @@ import org.joml.Vector3d;
 import org.joml.primitives.AABBdc;
 
 public class ProjectileArrow extends Projectile {
+    public static final int LIFETIME = 1200;
     public static final int TYPE_NORMAL = 0;
     public static final int TYPE_PURPLE = 1;
     public static final int TYPE_GOLDEN = 2;
@@ -129,7 +130,7 @@ public class ProjectileArrow extends Projectile {
                 return;
             }
             this.ticksInGround++;
-            if (this.ticksInGround == 1200) {
+            if (this.ticksInGround >= LIFETIME) {
                 remove();
             }
             return;
diff --git a/game/core/src/main/resources/lang/en_US/gamerules.lang b/game/core/src/main/resources/lang/en_US/gamerules.lang
index c3ba780c4..e760fb69a 100644
--- a/game/core/src/main/resources/lang/en_US/gamerules.lang
+++ b/game/core/src/main/resources/lang/en_US/gamerules.lang
@@ -24,3 +24,7 @@ gamerule.instant_healing.name=Instant Healing from Food
 gamerule.instant_healing.desc=If enabled, food will heal the player instantly as it did in older versions of BTA!.
 gamerule.random_tick_speed.name=Random Tick Rate
 gamerule.random_tick_speed.desc=Determines how many blocks are randomly ticked per game tick.
+gamerule.dropped_item_despawn_delay.name=Dropped Item Despawn Delay
+gamerule.dropped_item_despawn_delay.desc=The number of ticks until an item dropped by a player despawns.
+gamerule.item_despawn_delay.name=Item Despawn Delay
+gamerule.item_despawn_delay.desc=The number of ticks until an item that was not dropped by a player despawns.
