Fix MC-297591

Vanilla does not increment ticket timeouts if the chunk is
progressing in generation. They made this change in 1.21.6
so that the ender pearl ticket does not expire if the chunk
fails to generate before the timeout expires. Rather than
blindly adjusting the entire system behavior to fix this
small issue, we instead add non-expirable tickets to keep
ender pearls ticking.
This commit is contained in:
Spottedleaf
2025-06-20 12:52:11 -07:00
parent 9d58071cf5
commit 1f8e863c4b
7 changed files with 58 additions and 5 deletions

View File

@@ -271,4 +271,9 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
public long[] getCounterTypesUncached(final TicketType type) { public long[] getCounterTypesUncached(final TicketType type) {
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY; return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
} }
@Override
public boolean addTicketForEnderPearls() {
return true;
}
} }

View File

@@ -8,13 +8,13 @@ org.gradle.configuration-cache=true
minecraft_version=1.21.6 minecraft_version=1.21.6
loader_version=0.16.14 loader_version=0.16.14
supported_minecraft_versions=1.21.6 supported_minecraft_versions=1.21.6
neoforge_version=21.6.5-beta neoforge_version=21.6.11-beta
neoform_version=1.21.6-20250617.151856 neoform_version=1.21.6-20250617.151856
fabric_api_version=0.127.0+1.21.6 fabric_api_version=0.127.0+1.21.6
snakeyaml_version=2.3 snakeyaml_version=2.3
concurrentutil_version=0.0.3 concurrentutil_version=0.0.3
yamlconfig_version=1.0.2 yamlconfig_version=1.0.2
cloth_version=19.0.146 cloth_version=19.0.147
modmenu_version=15.0.0-beta.2 modmenu_version=15.0.0-beta.2
# set to false when modmenu/cloth is not updated for the current minecraft version # set to false when modmenu/cloth is not updated for the current minecraft version
enable_gui=true enable_gui=true

View File

@@ -286,4 +286,9 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
return ret.toLongArray(); return ret.toLongArray();
} }
@Override
public boolean addTicketForEnderPearls() {
return true;
}
} }

View File

@@ -102,6 +102,8 @@ public interface PlatformHooks extends ChunkSystemHooks {
public int modifyEntityTrackingRange(final Entity entity, final int currentRange); public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
public boolean addTicketForEnderPearls();
public static final class Holder { public static final class Holder {
private Holder() { private Holder() {
} }

View File

@@ -16,7 +16,8 @@ public final class CoordinateUtils {
} }
public static long getChunkKey(final Entity entity) { public static long getChunkKey(final Entity entity) {
return ((Mth.lfloor(entity.getZ()) >> 4) << 32) | ((Mth.lfloor(entity.getX()) >> 4) & 0xFFFFFFFFL); final ChunkPos pos = entity.chunkPosition();
return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL);
} }
public static long getChunkKey(final ChunkPos pos) { public static long getChunkKey(final ChunkPos pos) {

View File

@@ -45,8 +45,7 @@ public final class ClientEntityLookup extends EntityLookup {
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ)); final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
final ChunkEntitySlices ret = new ChunkEntitySlices( final ChunkEntitySlices ret = new ChunkEntitySlices(
this.world, chunkX, chunkZ, this.world, chunkX, chunkZ, ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world) WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
); );

View File

@@ -7,9 +7,14 @@ import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.projectile.ThrownEnderpearl;
import net.minecraft.world.level.entity.LevelCallback; import net.minecraft.world.level.entity.LevelCallback;
public final class ServerEntityLookup extends EntityLookup { public final class ServerEntityLookup extends EntityLookup {
@@ -19,6 +24,13 @@ public final class ServerEntityLookup extends EntityLookup {
private final ServerLevel serverWorld; private final ServerLevel serverWorld;
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
// Vanilla does not increment ticket timeouts if the chunk is progressing in generation. They made this change in 1.21.6 so that the ender pearl
// ticket does not expire if the chunk fails to generate before the timeout expires. Rather than blindly adjusting the entire system behavior
// to fix this small issue, we instead add non-expirable tickets here to keep ender pearls ticking. This is how the original feature should have
// been implemented, but I don't think Vanilla has proper entity add/remove hooks like we do. Fixes MC-297591
private static final TicketType ENDER_PEARL_TICKER = ChunkSystemTicketType.create("chunk_system:ender_pearl_ticker", null);
private final Long2IntOpenHashMap enderPearlChunkCount = new Long2IntOpenHashMap();
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) { public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
super(world, worldCallback); super(world, worldCallback);
this.serverWorld = world; this.serverWorld = world;
@@ -63,6 +75,10 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) { if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player); ((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
} }
if (entity instanceof ThrownEnderpearl enderpearl && (oldSectionX != newSectionX || oldSectionZ != newSectionZ)) {
this.removeEnderPearl(CoordinateUtils.getChunkKey(oldSectionX, oldSectionZ));
this.addEnderPearl(CoordinateUtils.getChunkKey(newSectionX, newSectionZ));
}
PlatformHooks.get().entityMove( PlatformHooks.get().entityMove(
entity, entity,
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ), CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
@@ -75,6 +91,9 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) { if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player); ((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
} }
if (entity instanceof ThrownEnderpearl enderpearl) {
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
}
} }
@Override @Override
@@ -82,6 +101,9 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) { if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player); ((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
} }
if (entity instanceof ThrownEnderpearl enderpearl) {
this.removeEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
}
} }
@Override @Override
@@ -112,4 +134,23 @@ public final class ServerEntityLookup extends EntityLookup {
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) { protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event); return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
} }
private void addEnderPearl(final long coordinate) {
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, 1);
if (oldCount != 0) {
return;
}
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
.addTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
}
private void removeEnderPearl(final long coordinate) {
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, -1);
if (oldCount != 1) {
return;
}
this.enderPearlChunkCount.remove(coordinate);
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
.removeTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
}
} }