Skip to content
Open
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,99 @@ 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..bdb12ee11716f622654a58e37b833d0a5cae94f0 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,10 @@ 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();
+ // Leaf start - Rewrite entity despawn time
+ private final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<Entity> weakEntities = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>();
+ public final it.unimi.dsi.fastutil.objects.ReferenceArrayList<Entity> weakEntityList = new it.unimi.dsi.fastutil.objects.ReferenceArrayList<>();
+ // Leaf end - Rewrite entity despawn time

public EntityLookup(final Level world, final LevelCallback<Entity> worldCallback) {
this.world = world;
@@ -257,6 +261,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.weakEntities.add(entity);
+ this.weakEntityList.add(entity);
+ } else if (!isWeakNow && wasWeakBefore) {
+ this.weakEntities.remove(entity);
+ }
+ }
+ }
+ // Leaf end - Rewrite entity despawn time
((ChunkSystemEntity)entity).moonrise$setUpdatingSectionStatus(true);
try {
if (created) {
@@ -497,6 +516,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) this.weakEntities.remove(entity); // 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 +955,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 || !this.weakEntities.contains(entity)) {
+ removeAtIndex(this.weakEntityList, i);
+ continue;
+ }
+
+ if (entity.isExceedingDespawnTime(true)) {
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ this.weakEntities.remove(entity);
+ 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 541c384187a0b20386ccc35200c7c4eb1ce62e9b..e41087a52c5c0521728357431afd182080ab1291 100644
index 541c384187a0b20386ccc35200c7c4eb1ce62e9b..f359a411bbde9c561d2ca68d6f5bac2336238ff5 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 +120,7 @@ index 541c384187a0b20386ccc35200c7c4eb1ce62e9b..e41087a52c5c0521728357431afd1820
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,12 +130,15 @@ index 541c384187a0b20386ccc35200c7c4eb1ce62e9b..e41087a52c5c0521728357431afd1820
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..bd1482ff66601d3f10a15ebd63f7fe90189f0500 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
Expand All @@ -69,7 +160,7 @@ index 1958a2e27df844bb2d9569fe63dd28df3f5227fe..8d092716cdcc48b829a1c0ee2e5416d6
}

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

public void tick() {
Expand All @@ -90,26 +181,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 +218,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 +2726,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 +2886,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name

// CraftBukkit start
// Spigot start
Expand All @@ -137,11 +235,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 +5484,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 @@ -7,7 +7,7 @@ The world border is only initialized once when the level is created.
Lookup from data storage map multiple time is quite unnecessary and expensive.

diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index e41087a52c5c0521728357431afd182080ab1291..cf2a365bcbb1a278e5553c16ffef6d9ae81f4d41 100644
index 0c13cf2a8c7dd90b311501dfb2c741e9b7dcc7b4..7f867328b03890fef1e9ff02ad6209e3312d2e5a 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -237,6 +237,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
Expand All @@ -18,7 +18,7 @@ index e41087a52c5c0521728357431afd182080ab1291..cf2a365bcbb1a278e5553c16ffef6d9a

@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.""",
"""
启用主动弱加载实体消失检查,
这是一个实验性功能。"""));
}
}