Skip to content

Commit 42f9551

Browse files
authored
cleanup despawn logic and add explanation (#565)
1 parent 89d7033 commit 42f9551

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

leaf-server/minecraft-patches/features/0304-Rewrite-entity-despawn-time.patch

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@ From: HaHaWTH <[email protected]>
33
Date: Tue, 9 Nov 2077 00:00:00 +0800
44
Subject: [PATCH] Rewrite entity despawn time
55

6+
HOW IT WORKS:
7+
In the default implementation, totalEntityAge only increments when an entity is actively ticked.
8+
Consequently, if an entity resides in a weak-loaded chunk, its aging process effectively pauses, allowing it to exist far beyond the configured despawn time.
9+
10+
This patch addresses this discrepancy by synchronizing entity age with absolute server time:
11+
Introduces lastTickTime to record the MinecraftServer.currentTick when an entity was last ticked.
12+
Once the entity is ticked again or unloaded, the system calculates the elapsed time (currentTick - lastTickTime), and adds it to the totalEntityAge.
13+
Also, it moves the despawn logic of projectiles to their own tick method (see ThrowableProjectile#tick), making it faster to despawn massive stuck projectiles.
14+
15+
Benchmarks (60,000 snowballs):
16+
Before: Around 120 seconds, server thread is struggling to process projectile physics.
17+
After: 1.5 seconds
18+
619
Brings the ability to despawn weak-loaded entities once they are ticked,
720
a solution for https://github.com/PaperMC/Paper/issues/12986
821

@@ -27,14 +40,14 @@ index f58b91b277ba85fa7c0e7ad10157ecbf10023065..b7f9f22abf60c75bc09126d9168fda9a
2740
for (Entity entity : passengerEntity.getPassengers()) {
2841
this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2
2942
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
30-
index f6d619709d4e5b0e6d1b943226579d7388835cdb..fefd0df22b32bb6f933bbf9530584c2c9616bfb6 100644
43+
index f6d619709d4e5b0e6d1b943226579d7388835cdb..137ec39c1458e6adc854df24807f0e26770d95da 100644
3144
--- a/net/minecraft/world/entity/Entity.java
3245
+++ b/net/minecraft/world/entity/Entity.java
3346
@@ -373,6 +373,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
3447
public boolean fixedPose = false; // Paper - Expand Pose API
3548
private final int despawnTime; // Paper - entity despawn time limit
3649
public int totalEntityAge; // Paper - age-like counter for all entities
37-
+ private int lastTickTicks; // Leaf - Rewrite entity despawn time
50+
+ private int lastTickTime; // Leaf - Rewrite entity despawn time
3851
public boolean activatedPriorityReset = false; // Pufferfish - DAB
3952
public int activatedPriority = org.dreeam.leaf.config.modules.opt.DynamicActivationofBrain.maximumActivationPrio; // Pufferfish - DAB (golf score)
4053
public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
@@ -54,7 +67,7 @@ index f6d619709d4e5b0e6d1b943226579d7388835cdb..fefd0df22b32bb6f933bbf9530584c2c
5467
}
5568

5669
public boolean isColliding(BlockPos pos, BlockState state) {
57-
@@ -887,15 +890,50 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
70+
@@ -887,15 +890,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
5871
}
5972

6073
public void tick() {
@@ -79,33 +92,29 @@ index f6d619709d4e5b0e6d1b943226579d7388835cdb..fefd0df22b32bb6f933bbf9530584c2c
7992
+ if (this.despawnTime >= 0) {
8093
+ int missedTicks = this.calculateMissedTicks();
8194
+ if (missedTicks > 1) {
82-
+ if ((this.totalEntityAge += missedTicks) >= this.despawnTime) {
83-
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
84-
+ return true;
85-
+ }
86-
+ } else {
87-
+ if (this.totalEntityAge >= this.despawnTime) {
88-
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
89-
+ return true;
90-
+ }
95+
+ this.totalEntityAge += missedTicks;
96+
+ }
97+
+ if (this.totalEntityAge >= this.despawnTime) {
98+
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
99+
+ return true;
91100
+ }
92101
+ }
93102
+ return false;
94103
+ }
95104
+
96105
+ private int calculateMissedTicks() {
97-
+ return net.minecraft.server.MinecraftServer.currentTick - this.lastTickTicks;
106+
+ return net.minecraft.server.MinecraftServer.currentTick - this.lastTickTime;
98107
+ }
99108
+
100109
+ public void updateLastTick() {
101-
+ this.lastTickTicks = net.minecraft.server.MinecraftServer.currentTick;
110+
+ this.lastTickTime = net.minecraft.server.MinecraftServer.currentTick;
102111
+ }
103112
+ // Leaf end - Rewrite entity despawn time
104113
+
105114
// CraftBukkit start
106115
public void postTick() {
107116
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
108-
@@ -2564,6 +2602,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
117+
@@ -2564,6 +2598,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
109118
if (this.maxAirTicks != this.getDefaultMaxAirSupply()) {
110119
output.putInt("Bukkit.MaxAirSupply", this.getMaxAirSupply());
111120
}

0 commit comments

Comments
 (0)