diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_entity_remove/LevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_entity_remove/LevelMixin.java index 40eb75b..8f49669 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_entity_remove/LevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_entity_remove/LevelMixin.java @@ -1,5 +1,6 @@ package ca.spottedleaf.moonrise.mixin.block_entity_remove; +import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.BlockPos; import net.minecraft.world.TickRateManager; @@ -73,6 +74,8 @@ public abstract class LevelMixin implements LevelAccessor, AutoCloseable { int i = 0; // current ticking entity (exclusive) int len = tickList.size(); + int tickedEntities = 0; + Objects.checkFromToIndex(0, len, elements.length); try { for (; i < len; ++i) { @@ -84,6 +87,10 @@ public abstract class LevelMixin implements LevelAccessor, AutoCloseable { if (doTick && this.shouldTickBlocksAt(tileEntity.getPos())) { tileEntity.tick(); + // call mid tick tasks for chunk system + if ((++tickedEntities & 7) == 0) { + ((ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks(); + } } if (writeToBase) { diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/EntityTickListMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/EntityTickListMixin.java index 3094ae7..e2dcacf 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/EntityTickListMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/EntityTickListMixin.java @@ -111,6 +111,6 @@ public abstract class EntityTickListMixin { } } finally { iterator.finishedIterating(); - } + } } } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/LevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/LevelMixin.java index b4a0167..64d2ca4 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/LevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/LevelMixin.java @@ -189,6 +189,11 @@ public abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityG return this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, false); } + @Override + public void moonrise$midTickTasks() { + // no-op on ClientLevel + } + /** * @reason Allow block updates in non-ticking chunks, as new chunk system sends non-ticking chunks to clients * @author Spottedleaf @@ -207,4 +212,21 @@ public abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityG } // TODO: Thread.currentThread() != this.thread to TickThread? + + + /** + * @reason Execute mid-tick chunk tasks during entity ticking + * @author Spottedleaf + */ + @Inject( + method = "guardEntityTick", + at = @At( + value = "INVOKE", + shift = At.Shift.AFTER, + target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V" + ) + ) + private void midTickEntity(final CallbackInfo ci) { + this.moonrise$midTickTasks(); + } } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/MinecraftServerMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/MinecraftServerMixin.java index aae0537..cea9978 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/MinecraftServerMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/MinecraftServerMixin.java @@ -55,13 +55,84 @@ public abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop= MAX_CHUNK_EXEC_TIME) { + if (!moreTasks) { + this.lastMidTickExecuteFailure = currTime; + } + + // note: negative values reduce the time + long overuse = diff - MAX_CHUNK_EXEC_TIME; + if (overuse >= (10L * 1000L * 1000L)) { // 10ms + // make sure something like a GC or dumb plugin doesn't screw us over... + overuse = 10L * 1000L * 1000L; // 10ms + } + + final double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME; + final long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME); + + this.lastMidTickExecute = currTime + extraSleep; + return; + } + } + } + /** - * @reason Force execution of tasks for all worlds, so that the first world does not hog all of the task processing + * @reason Force execution of tasks for all worlds, so that the first world does not hog the task processing time. + * Additionally, perform mid-tick task execution when handling the normal server queue so that chunk tasks + * are guaranteed to be processed during tick sleep. * @author Spottedleaf */ @Overwrite private boolean pollTaskInternal() { if (super.pollTask()) { + this.moonrise$executeMidTickTasks(); return true; } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java index f86c300..c47e1b9 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerChunkCacheMixin.java @@ -8,6 +8,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder; +import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer; import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkLevel; @@ -48,6 +49,9 @@ public abstract class ServerChunkCacheMixin extends ChunkSource implements Chunk @Unique private final ConcurrentLong2ReferenceChainedHashTable fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>(); + @Unique + private long chunksTicked; + @Override public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) { final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ); @@ -274,4 +278,24 @@ public abstract class ServerChunkCacheMixin extends ChunkSource implements Chunk private boolean skipSaveTicketUpdates(final ServerChunkCache instance) { return false; } + + /** + * @reason Perform mid-tick chunk task processing during chunk tick + * @author Spottedleaf + */ + @Inject( + method = "tickChunks", + at = @At( + value = "INVOKE", + shift = At.Shift.AFTER, + target = "Lnet/minecraft/server/level/ServerLevel;tickChunk(Lnet/minecraft/world/level/chunk/LevelChunk;I)V" + ) + ) + private void midTickChunks(final CallbackInfo ci) { + if ((++this.chunksTicked & 7L) != 0L) { + return; + } + + ((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks(); + } } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java index c84f057..8f2a1f7 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java @@ -15,6 +15,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManage import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ThreadedTicketLevelPropagator; +import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; @@ -43,6 +44,7 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.ServerLevelData; import net.minecraft.world.level.storage.WritableLevelData; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -67,6 +69,10 @@ public abstract class ServerLevelMixin extends Level implements ChunkSystemServe @Shadow private PersistentEntitySectionManager entityManager; + @Shadow + @Final + private MinecraftServer server; + protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey resourceKey, RegistryAccess registryAccess, Holder holder, Supplier supplier, boolean bl, boolean bl2, long l, int i) { super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i); } @@ -92,6 +98,12 @@ public abstract class ServerLevelMixin extends Level implements ChunkSystemServe @Unique private ChunkTaskScheduler chunkTaskScheduler; + @Unique + private long lastMidTickFailure; + + @Unique + private long tickedBlocksOrFluids; + /** * @reason Initialise fields / destroy entity manager state * @author Spottedleaf @@ -153,6 +165,11 @@ public abstract class ServerLevelMixin extends Level implements ChunkSystemServe return newChunkHolder.getChunkIfPresentUnchecked(leastStatus); } + @Override + public final void moonrise$midTickTasks() { + ((ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); + } + @Override public final ChunkAccess moonrise$syncLoadNonFull(final int chunkX, final int chunkZ, final ChunkStatus status) { return this.moonrise$getChunkTaskScheduler().syncLoadNonFull(chunkX, chunkZ, status); @@ -279,6 +296,16 @@ public abstract class ServerLevelMixin extends Level implements ChunkSystemServe return this.viewDistanceHolder; } + @Override + public final long moonrise$getLastMidTickFailure() { + return this.lastMidTickFailure; + } + + @Override + public final void moonrise$setLastMidTickFailure(final long time) { + this.lastMidTickFailure = time; + } + /** * @reason Entities are guaranteed to be ticking in the new chunk system * @author Spottedleaf @@ -600,4 +627,38 @@ public abstract class ServerLevelMixin extends Level implements ChunkSystemServe private int redirectCrashCount(final PersistentEntitySectionManager instance) { return this.moonrise$getEntityLookup().getEntityCount(); } + + /** + * @reason Execute mid-tick chunk tasks during fluid ticking + * @author Spottedleaf + */ + @Inject( + method = "tickFluid", + at = @At( + value = "RETURN" + ) + ) + private void midTickFluids(final CallbackInfo ci) { + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { + return; + } + ((ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); + } + + /** + * @reason Execute mid-tick chunk tasks during block ticking + * @author Spottedleaf + */ + @Inject( + method = "tickBlock", + at = @At( + value = "RETURN" + ) + ) + private void midTickBlock(final CallbackInfo ci) { + if ((++this.tickedBlocksOrFluids & 7L) != 0L) { + return; + } + ((ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); + } } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java index eab0994..efcd905 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemLevel.java @@ -17,4 +17,6 @@ public interface ChunkSystemLevel { public ChunkAccess moonrise$getSpecificChunkIfLoaded(final int chunkX, final int chunkZ, final ChunkStatus leastStatus); + public void moonrise$midTickTasks(); + } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java index a31c392..becb002 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/ChunkSystemServerLevel.java @@ -46,4 +46,7 @@ public interface ChunkSystemServerLevel extends ChunkSystemLevel { public RegionizedPlayerChunkLoader.ViewDistanceHolder moonrise$getViewDistanceHolder(); + public long moonrise$getLastMidTickFailure(); + + public void moonrise$setLastMidTickFailure(final long time); } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/server/ChunkSystemMinecraftServer.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/server/ChunkSystemMinecraftServer.java index 21c9562..cb6af37 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/server/ChunkSystemMinecraftServer.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/server/ChunkSystemMinecraftServer.java @@ -4,4 +4,6 @@ public interface ChunkSystemMinecraftServer { public void moonrise$setChunkSystemCrash(final Throwable throwable); + public void moonrise$executeMidTickTasks(); + }