Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,96 @@ After: 1.5 seconds
Brings the ability to despawn weak-loaded entities once they are ticked,
a solution for https://github.com/PaperMC/Paper/issues/12986

diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
index 703bf9c2a56b262e2719a1787584de537b8f12e0..c1d24cff2af534edfb9fcc45f3cf2b31eb04c6de 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
@@ -51,6 +51,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
protected final ConcurrentLong2ReferenceChainedHashTable<Entity> entityById = new ConcurrentLong2ReferenceChainedHashTable<>();
protected final ConcurrentHashMap<UUID, Entity> entityByUUID = new ConcurrentHashMap<>();
protected final EntityList accessibleEntities = new EntityList();
+ public final it.unimi.dsi.fastutil.objects.ReferenceArrayList<Entity> weakEntityList = new it.unimi.dsi.fastutil.objects.ReferenceArrayList<>(); // Leaf - Rewrite entity despawn time

public EntityLookup(final Level world, final LevelCallback<Entity> worldCallback) {
this.world = world;
@@ -257,6 +258,21 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
try {
final Boolean ticketBlockBefore = this.blockTicketUpdates();
try {
+ // Leaf start - Rewrite entity despawn time
+ if (org.dreeam.leaf.config.modules.opt.DespawnTime.proactiveWeakLoading) {
+ boolean isWeakNow = newVisibility == Visibility.TRACKED;
+ boolean wasWeakBefore = oldVisibility == Visibility.TRACKED;
+
+ if (entity.despawnTime >= 0) {
+ if (isWeakNow && !wasWeakBefore) {
+ this.weakEntityList.add(entity);
+ entity.leaf$isWeakLoaded = true;
+ } else if (!isWeakNow && wasWeakBefore) {
+ entity.leaf$isWeakLoaded = false;
+ }
+ }
+ }
+ // Leaf end - Rewrite entity despawn time
((ChunkSystemEntity)entity).moonrise$setUpdatingSectionStatus(true);
try {
if (created) {
@@ -497,6 +513,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
LOGGER.warn("Failed to remove entity " + entity + " from entity slices (" + sectionX + "," + sectionZ + ")");
}
}
+ if (org.dreeam.leaf.config.modules.opt.DespawnTime.proactiveWeakLoading) entity.leaf$isWeakLoaded = false; // Leaf - Rewrite entity despawn time
((ChunkSystemEntity)entity).moonrise$setSectionX(Integer.MIN_VALUE);
((ChunkSystemEntity)entity).moonrise$setSectionY(Integer.MIN_VALUE);
((ChunkSystemEntity)entity).moonrise$setSectionZ(Integer.MIN_VALUE);
@@ -935,6 +952,34 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
}
}

+ // Leaf start - Rewrite entity despawn time
+ public void leaf$tickWeakEntities() {
+ if (this.weakEntityList.isEmpty()) return;
+
+ for (int i = this.weakEntityList.size() - 1; i >= 0; i--) {
+ Entity entity = this.weakEntityList.get(i);
+
+ if (entity == null || !entity.leaf$isWeakLoaded) {
+ removeAtIndex(this.weakEntityList, i);
+ continue;
+ }
+
+ if (entity.isExceedingDespawnTime(true)) {
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ entity.leaf$isWeakLoaded = false;
+ removeAtIndex(this.weakEntityList, i);
+ }
+ }
+ }
+
+ private static void removeAtIndex(List<Entity> list, int index) {
+ int lastIndex = list.size() - 1;
+ if (index != lastIndex) {
+ list.set(index, list.get(lastIndex));
+ }
+ list.remove(lastIndex);
+ }
+ // Leaf end - Rewrite entity despawn time
public static final class ChunkSlicesRegion {

private final ChunkEntitySlices[] slices = new ChunkEntitySlices[REGION_SIZE * REGION_SIZE];
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 56ece83a961d91883627148da7542630a7e09a30..8e8c083a86384817c0534bcd10590e62fa035e0f 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1613,6 +1613,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1061,6 +1061,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.debugSynchronizers.tick(this.server.debugSubscribers());
profilerFiller.pop();
this.environmentAttributes().invalidateTickCache();
+ if (org.dreeam.leaf.config.modules.opt.DespawnTime.proactiveWeakLoading) this.moonrise$getEntityLookup().leaf$tickWeakEntities(); // Leaf - Rewrite entity despawn time
if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) { this.leaf$asyncTracker.onEntitiesTickEnd(); } // Leaf - Multithreaded tracker
}

@@ -1613,6 +1614,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} else {entity.inactiveTick();} // Paper - EAR 2
profilerFiller.pop();

Expand All @@ -32,7 +117,7 @@ index 56ece83a961d91883627148da7542630a7e09a30..8e8c083a86384817c0534bcd10590e62
for (Entity entity1 : entity.getPassengers()) {
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
}
@@ -1641,6 +1643,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1641,6 +1644,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - EAR 2
profilerFiller.pop();

Expand All @@ -42,34 +127,45 @@ index 56ece83a961d91883627148da7542630a7e09a30..8e8c083a86384817c0534bcd10590e62
this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2
}
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..8d092716cdcc48b829a1c0ee2e5416d648143a37 100644
index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..a6890585cd08ad255939fa23b7286f3d3eb0cebe 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -377,6 +377,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -375,8 +375,9 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
// Paper end
public boolean freezeLocked = false; // Paper - Freeze Tick Lock API
public boolean fixedPose = false; // Paper - Expand Pose API
private final int despawnTime; // Paper - entity despawn time limit
- private final int despawnTime; // Paper - entity despawn time limit
+ public final int despawnTime; // Paper - entity despawn time limit // Leaf - Rewrite entity despawn time - private -> public
public int totalEntityAge; // Paper - age-like counter for all entities
+ private int lastTickTime; // Leaf - Rewrite entity despawn time
public boolean activatedPriorityReset = false; // Pufferfish - DAB
public int activatedPriority = org.dreeam.leaf.config.modules.opt.DynamicActivationofBrain.maximumActivationPrio; // Pufferfish - DAB (golf score)
public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
@@ -405,6 +406,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -386,6 +387,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
public boolean isTemporarilyActive;
public long activatedImmunityTick = Integer.MIN_VALUE;
public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API
+ public boolean leaf$isWeakLoaded = false; // Leaf - Rewrite entity despawn time

public void inactiveTick() {
}
@@ -405,6 +407,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
private int sectionY = Integer.MIN_VALUE;
private int sectionZ = Integer.MIN_VALUE;
private boolean updatingSectionStatus;
+ private final boolean shouldSkipBaseDespawnCheck = this instanceof net.minecraft.world.entity.projectile.ThrowableProjectile; // Leaf - Rewrite entity despawn time

@Override
public final boolean moonrise$isHardColliding() {
@@ -629,6 +631,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -629,6 +632,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
this.setPos(0.0, 0.0, 0.0);
this.eyeHeight = this.dimensions.eyeHeight();
this.despawnTime = level == null || type == EntityType.PLAYER ? -1 : level.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit
+ this.updateLastTick(); // Leaf - Rewrite entity despawn time
}

public boolean isColliding(BlockPos pos, BlockState state) {
@@ -898,15 +901,50 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -898,15 +902,57 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
}

public void tick() {
Expand All @@ -90,26 +186,33 @@ index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..8d092716cdcc48b829a1c0ee2e5416d6
}

+ // Leaf start - Rewrite entity despawn time
+ protected final boolean detectDespawnTime() {
+ this.syncEntityAge();
+ if (this.despawnTime >= 0) {
+ if (this.totalEntityAge >= this.despawnTime) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ return true;
+ }
+ private int calculateMissedTicks() {
+ return net.minecraft.server.MinecraftServer.currentTick - this.lastTickTime;
+ }
+
+ public final boolean detectDespawnTime() {
+ boolean exceeded = this.isExceedingDespawnTime(false);
+ if (exceeded) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ }
+ return false;
+ return exceeded;
+ }
+
+ private int calculateMissedTicks() {
+ return net.minecraft.server.MinecraftServer.currentTick - this.lastTickTime;
+ public final boolean isExceedingDespawnTime(boolean isWeakLoaded) {
+ if (this.despawnTime >= 0) {
+ int compensatedAge = this.syncEntityAge(!isWeakLoaded);
+ return compensatedAge >= this.despawnTime;
+ }
+ return false;
+ }
+
+ private void syncEntityAge() {
+ private int syncEntityAge(boolean writeBack) {
+ int missedTicks = this.calculateMissedTicks();
+ if (missedTicks > 1) {
+ this.totalEntityAge += missedTicks;
+ if (writeBack) return this.totalEntityAge += missedTicks;
+ return this.totalEntityAge + missedTicks;
+ }
+ return this.totalEntityAge;
+ }
+
+ public void updateLastTick() {
Expand All @@ -120,15 +223,15 @@ index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..8d092716cdcc48b829a1c0ee2e5416d6
// CraftBukkit start
public void postTick() {
// 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
@@ -2681,6 +2719,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -2681,6 +2727,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
if (this.maxAirTicks != this.getDefaultMaxAirSupply() && this.getDefaultMaxAirSupply() != this.level().purpurConfig.drowningAirTicks) { // Purpur - Drowning Settings
output.putInt("Bukkit.MaxAirSupply", this.getMaxAirSupply());
}
+ this.syncEntityAge(); // Leaf - Rewrite entity despawn time
+ this.syncEntityAge(true); // Leaf - Rewrite entity despawn time
output.putInt("Spigot.ticksLived", this.totalEntityAge); // Paper
// CraftBukkit end
output.storeNullable("CustomName", ComponentSerialization.CODEC, this.getCustomName());
@@ -2840,7 +2879,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -2840,7 +2887,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name

// CraftBukkit start
// Spigot start
Expand All @@ -137,11 +240,11 @@ index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..8d092716cdcc48b829a1c0ee2e5416d6
this.totalEntityAge = input.getIntOr("Spigot.ticksLived", 0); // Paper
}
// Spigot end
@@ -5438,9 +5477,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
@@ -5438,9 +5485,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name

@Override
public boolean shouldBeSaved() {
+ this.syncEntityAge(); // Leaf - Rewrite entity despawn time
+ this.syncEntityAge(true); // Leaf - Rewrite entity despawn time
return (this.removalReason == null || this.removalReason.shouldSave())
&& !this.isPassenger()
- && (!this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Paper - rewrite chunk system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ index 8e8c083a86384817c0534bcd10590e62fa035e0f..b94a5ff96b6800752d8a19d8132c25c4

@Override
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
@@ -2517,8 +2518,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -2518,8 +2519,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe

@Override
public WorldBorder getWorldBorder() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.dreeam.leaf.config.modules.opt;

import org.dreeam.leaf.config.ConfigModules;
import org.dreeam.leaf.config.EnumConfigCategory;
import org.dreeam.leaf.config.annotations.Experimental;

public class DespawnTime extends ConfigModules {

public String getBasePath() {
return EnumConfigCategory.PERF.getBaseKeyName() + ".despawn-time";
}

@Experimental
public static boolean proactiveWeakLoading = false;

@Override
public void onLoaded() {
proactiveWeakLoading = config.getBoolean(getBasePath() + ".proactive-weak-loading-despawn", proactiveWeakLoading,
config.pickStringRegionBased("""
Proactive despawn check for weak-loaded entities.
This is an experimental feature.""",
"""
启用主动弱加载实体消失检查,
这是一个实验性功能。"""));
}
}