From c11a88d1baf062bf0c754e2ece85b3eca954e406 Mon Sep 17 00:00:00 2001 From: Sotr Date: Tue, 12 Jun 2018 15:46:52 +0800 Subject: [PATCH] Fixes chunk unloading --- .../mixin/cps/MixinChunkProviderServer.java | 36 +++++++++---------- .../server/mixin/cps/MixinCraftWorld.java | 28 ++++----------- .../server/mixin/lighting/MixinChunk.java | 2 +- .../mixin/lighting/MixinWorldServer.java | 29 +++++++-------- 4 files changed, 39 insertions(+), 56 deletions(-) diff --git a/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunkProviderServer.java b/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunkProviderServer.java index aaa89c347..56f6e5e12 100644 --- a/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunkProviderServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/cps/MixinChunkProviderServer.java @@ -10,6 +10,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import io.akarin.api.Akari; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.server.Chunk; import net.minecraft.server.ChunkProviderServer; @@ -39,37 +40,34 @@ public abstract class MixinChunkProviderServer { @Overwrite public boolean unloadChunks() { if (!this.world.savingDisabled) { - SlackActivityAccountant activityAccountant = world.getMinecraftServer().slackActivityAccountant; - activityAccountant.startActivity(0.5); - - Iterator it = chunks.values().iterator(); long now = System.currentTimeMillis(); long unloadAfter = world.paperConfig.delayChunkUnloadsBy; - int targetSize = Math.min(pendingUnloadChunks - 100, (int) (pendingUnloadChunks * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive + SlackActivityAccountant activityAccountant = world.getMinecraftServer().slackActivityAccountant; + Iterator it = chunks.values().iterator(); - while (it.hasNext() && pendingUnloadChunks > targetSize) { + while (it.hasNext()) { + activityAccountant.startActivity(0.5); + Chunk chunk = it.next(); + if (unloadAfter > 0) { + if (chunk.scheduledForUnload != null && now - chunk.scheduledForUnload > unloadAfter) { + chunk.scheduledForUnload = null; + unload(chunk); + } + } + int targetSize = Math.min(pendingUnloadChunks - 100, (int) (pendingUnloadChunks * UNLOAD_QUEUE_RESIZE_FACTOR)); // Paper - Make more aggressive if (chunk != null && chunk.isUnloading()) { - if (unloadAfter > 0) { - // We changed Paper's delay unload logic, the original behavior is just mark as unloading - if (chunk.scheduledForUnload == null || now - chunk.scheduledForUnload < unloadAfter) { - continue; - } - chunk.scheduledForUnload = null; - } - // If a plugin cancelled it, we shouldn't trying unload it for a while chunk.setShouldUnload(false); // Paper if (!unloadChunk(chunk, true)) continue; // Event cancelled - pendingUnloadChunks--; it.remove(); - if (activityAccountant.activityTimeIsExhausted()) break; + if (--pendingUnloadChunks <= targetSize && activityAccountant.activityTimeIsExhausted()) break; } + activityAccountant.endActivity(); } - activityAccountant.endActivity(); this.chunkLoader.b(); // PAIL: chunkTick } return false; @@ -77,9 +75,9 @@ public abstract class MixinChunkProviderServer { @Redirect(method = "unloadChunk", at = @At( value = "INVOKE", - target = "it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.remove(J)Lnet/minecraft/server/Chunk;" + target = "it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.remove(J)Ljava/lang/Object;" )) - private Chunk remove(Long2ObjectOpenHashMap chunks, Object chunkHash) { + private Object remove(Long2ObjectOpenHashMap chunks, long chunkHash) { return null; } diff --git a/sources/src/main/java/io/akarin/server/mixin/cps/MixinCraftWorld.java b/sources/src/main/java/io/akarin/server/mixin/cps/MixinCraftWorld.java index 1c9251778..015d3696e 100644 --- a/sources/src/main/java/io/akarin/server/mixin/cps/MixinCraftWorld.java +++ b/sources/src/main/java/io/akarin/server/mixin/cps/MixinCraftWorld.java @@ -4,24 +4,16 @@ import java.util.Set; import org.bukkit.craftbukkit.CraftWorld; import org.spongepowered.asm.lib.Opcodes; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.Inject; - -import net.minecraft.server.Chunk; -import net.minecraft.server.PlayerChunk; +import net.minecraft.server.WorldServer; @Mixin(value = CraftWorld.class, remap = false) public class MixinCraftWorld { - @Inject(method = "processChunkGC()V", at = @At( - value = "INVOKE", - target = "net/minecraft/server/ChunkProviderServer.unload(Lnet/minecraft/server/Chunk;)V" - )) - public void cancelUnloading(Chunk chunk, CallbackInfo ci) { - if (chunk.isUnloading()) ci.cancel(); - } + @Shadow @Final private WorldServer world; @Redirect(method = "processChunkGC()V", at = @At( value = "INVOKE", @@ -38,15 +30,7 @@ public class MixinCraftWorld { opcode = Opcodes.INVOKEINTERFACE )) public boolean regenChunk(Set set, Object chunkHash) { - return false; - } - - @Inject(method = "processChunkGC()V", at = @At( - value = "FIELD", - target = "net/minecraft/server/PlayerChunk.chunk:Lnet/minecraft/server/Chunk;", - opcode = Opcodes.PUTFIELD - )) - public void noUnload(PlayerChunk playerChunk, Chunk chunk, CallbackInfo ci) { - chunk.setShouldUnload(false); + world.getChunkProviderServer().unload(world.getChunkProviderServer().chunks.get(chunkHash)); + return true; } } diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java index 90894dd17..76f586368 100644 --- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java +++ b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java @@ -245,7 +245,7 @@ public abstract class MixinChunk implements IMixinChunk { return; } - if (Akari.isPrimaryThread()) { // Akarin + if (Akari.isPrimaryThread()) { try { this.lightExecutorService.execute(() -> { this.checkLightAsync(neighborChunks); diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java index 8039a3839..fdccd4036 100644 --- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java @@ -30,6 +30,7 @@ import java.util.concurrent.Executors; import javax.annotation.Nullable; import org.spongepowered.asm.mixin.Mixin; + import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.akarin.api.Akari; @@ -92,9 +93,9 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld int k2 = (l1 >> 12 & 63) - 32 + z; int l2 = l1 >> 18 & 15; BlockPosition blockpos = new BlockPosition(i2, j2, k2); - int i3 = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors); // Sponge - use thread safe method + int lightLevel = this.getLightForAsync(lightType, blockpos, currentChunk, neighbors); // Sponge - use thread safe method - if (i3 == l2) { + if (lightLevel == l2) { this.setLightForAsync(lightType, blockpos, 0, currentChunk, neighbors); // Sponge - use thread safe method if (l2 > 0) { @@ -103,28 +104,28 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld int l3 = MathHelper.a(k2 - z); if (j3 + k3 + l3 < 17) { - PooledBlockPosition blockpos$pooledmutableblockpos = PooledBlockPosition.aquire(); - + PooledBlockPosition mutableBlockpos = PooledBlockPosition.aquire(); + for (EnumDirection enumfacing : EnumDirection.values()) { int i4 = i2 + enumfacing.getAdjacentX(); int j4 = j2 + enumfacing.getAdjacentX(); int k4 = k2 + enumfacing.getAdjacentX(); - blockpos$pooledmutableblockpos.setValues(i4, j4, k4); + mutableBlockpos.setValues(i4, j4, k4); // Sponge start - get chunk safely - final Chunk pooledChunk = this.getLightChunk(blockpos$pooledmutableblockpos, currentChunk, neighbors); + final Chunk pooledChunk = this.getLightChunk(mutableBlockpos, currentChunk, neighbors); if (pooledChunk == null) { continue; } - int l4 = Math.max(1, pooledChunk.getBlockData(blockpos$pooledmutableblockpos).c()); // PAIL: getLightOpacity - i3 = this.getLightForAsync(lightType, blockpos$pooledmutableblockpos, currentChunk, neighbors); + int opacity = Math.max(1, pooledChunk.getBlockData(mutableBlockpos).c()); // PAIL: getLightOpacity + lightLevel = this.getLightForAsync(lightType, mutableBlockpos, currentChunk, neighbors); // Sponge end - - if (i3 == l2 - l4 && j < this.J.length) { // PAIL: lightUpdateBlockList - this.J[j++] = i4 - x + 32 | j4 - y + 32 << 6 | k4 - z + 32 << 12 | l2 - l4 << 18; // PAIL: lightUpdateBlockList + + if (lightLevel == l2 - opacity && j < this.J.length) { // PAIL: lightUpdateBlockList + this.J[j++] = i4 - x + 32 | j4 - y + 32 << 6 | k4 - z + 32 << 12 | l2 - opacity << 18; // PAIL: lightUpdateBlockList } } - blockpos$pooledmutableblockpos.free(); + mutableBlockpos.free(); } } } @@ -181,7 +182,7 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld } } } - + // Sponge start - Asynchronous light updates spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos)); spongeChunk.getPendingLightUpdates().decrementAndGet(); @@ -296,7 +297,7 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld return chunk.getBrightness(lightType, pos); } - + private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List neighbors) { final Chunk chunk = getLightChunk(pos, currentChunk, neighbors); if (chunk == null || chunk.isUnloading()) {