Fixes chunk unloading

This commit is contained in:
Sotr
2018-06-12 15:46:52 +08:00
parent 9626867217
commit c11a88d1ba
4 changed files with 39 additions and 56 deletions

View File

@@ -10,6 +10,7 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import io.akarin.api.Akari;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.server.Chunk; import net.minecraft.server.Chunk;
import net.minecraft.server.ChunkProviderServer; import net.minecraft.server.ChunkProviderServer;
@@ -39,37 +40,34 @@ public abstract class MixinChunkProviderServer {
@Overwrite @Overwrite
public boolean unloadChunks() { public boolean unloadChunks() {
if (!this.world.savingDisabled) { if (!this.world.savingDisabled) {
SlackActivityAccountant activityAccountant = world.getMinecraftServer().slackActivityAccountant;
activityAccountant.startActivity(0.5);
Iterator<Chunk> it = chunks.values().iterator();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long unloadAfter = world.paperConfig.delayChunkUnloadsBy; 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<Chunk> it = chunks.values().iterator();
while (it.hasNext() && pendingUnloadChunks > targetSize) { while (it.hasNext()) {
activityAccountant.startActivity(0.5);
Chunk chunk = it.next(); 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 (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 // If a plugin cancelled it, we shouldn't trying unload it for a while
chunk.setShouldUnload(false); // Paper chunk.setShouldUnload(false); // Paper
if (!unloadChunk(chunk, true)) continue; // Event cancelled if (!unloadChunk(chunk, true)) continue; // Event cancelled
pendingUnloadChunks--;
it.remove(); it.remove();
if (activityAccountant.activityTimeIsExhausted()) break; if (--pendingUnloadChunks <= targetSize && activityAccountant.activityTimeIsExhausted()) break;
} }
activityAccountant.endActivity();
} }
activityAccountant.endActivity();
this.chunkLoader.b(); // PAIL: chunkTick this.chunkLoader.b(); // PAIL: chunkTick
} }
return false; return false;
@@ -77,9 +75,9 @@ public abstract class MixinChunkProviderServer {
@Redirect(method = "unloadChunk", at = @At( @Redirect(method = "unloadChunk", at = @At(
value = "INVOKE", 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<Chunk> chunks, Object chunkHash) { private Object remove(Long2ObjectOpenHashMap<Chunk> chunks, long chunkHash) {
return null; return null;
} }

View File

@@ -4,24 +4,16 @@ import java.util.Set;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.server.WorldServer;
import org.spongepowered.asm.mixin.injection.Inject;
import net.minecraft.server.Chunk;
import net.minecraft.server.PlayerChunk;
@Mixin(value = CraftWorld.class, remap = false) @Mixin(value = CraftWorld.class, remap = false)
public class MixinCraftWorld { public class MixinCraftWorld {
@Inject(method = "processChunkGC()V", at = @At( @Shadow @Final private WorldServer world;
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();
}
@Redirect(method = "processChunkGC()V", at = @At( @Redirect(method = "processChunkGC()V", at = @At(
value = "INVOKE", value = "INVOKE",
@@ -38,15 +30,7 @@ public class MixinCraftWorld {
opcode = Opcodes.INVOKEINTERFACE opcode = Opcodes.INVOKEINTERFACE
)) ))
public boolean regenChunk(Set<Long> set, Object chunkHash) { public boolean regenChunk(Set<Long> set, Object chunkHash) {
return false; world.getChunkProviderServer().unload(world.getChunkProviderServer().chunks.get(chunkHash));
} return true;
@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);
} }
} }

View File

@@ -245,7 +245,7 @@ public abstract class MixinChunk implements IMixinChunk {
return; return;
} }
if (Akari.isPrimaryThread()) { // Akarin if (Akari.isPrimaryThread()) {
try { try {
this.lightExecutorService.execute(() -> { this.lightExecutorService.execute(() -> {
this.checkLightAsync(neighborChunks); this.checkLightAsync(neighborChunks);

View File

@@ -30,6 +30,7 @@ import java.util.concurrent.Executors;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.akarin.api.Akari; 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 k2 = (l1 >> 12 & 63) - 32 + z;
int l2 = l1 >> 18 & 15; int l2 = l1 >> 18 & 15;
BlockPosition blockpos = new BlockPosition(i2, j2, k2); 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 this.setLightForAsync(lightType, blockpos, 0, currentChunk, neighbors); // Sponge - use thread safe method
if (l2 > 0) { if (l2 > 0) {
@@ -103,28 +104,28 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
int l3 = MathHelper.a(k2 - z); int l3 = MathHelper.a(k2 - z);
if (j3 + k3 + l3 < 17) { if (j3 + k3 + l3 < 17) {
PooledBlockPosition blockpos$pooledmutableblockpos = PooledBlockPosition.aquire(); PooledBlockPosition mutableBlockpos = PooledBlockPosition.aquire();
for (EnumDirection enumfacing : EnumDirection.values()) { for (EnumDirection enumfacing : EnumDirection.values()) {
int i4 = i2 + enumfacing.getAdjacentX(); int i4 = i2 + enumfacing.getAdjacentX();
int j4 = j2 + enumfacing.getAdjacentX(); int j4 = j2 + enumfacing.getAdjacentX();
int k4 = k2 + enumfacing.getAdjacentX(); int k4 = k2 + enumfacing.getAdjacentX();
blockpos$pooledmutableblockpos.setValues(i4, j4, k4); mutableBlockpos.setValues(i4, j4, k4);
// Sponge start - get chunk safely // 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) { if (pooledChunk == null) {
continue; continue;
} }
int l4 = Math.max(1, pooledChunk.getBlockData(blockpos$pooledmutableblockpos).c()); // PAIL: getLightOpacity int opacity = Math.max(1, pooledChunk.getBlockData(mutableBlockpos).c()); // PAIL: getLightOpacity
i3 = this.getLightForAsync(lightType, blockpos$pooledmutableblockpos, currentChunk, neighbors); lightLevel = this.getLightForAsync(lightType, mutableBlockpos, currentChunk, neighbors);
// Sponge end // Sponge end
if (i3 == l2 - l4 && j < this.J.length) { // 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 - l4 << 18; // 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 // Sponge start - Asynchronous light updates
spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos)); spongeChunk.getQueuedLightingUpdates(lightType).remove((Short) this.blockPosToShort(pos));
spongeChunk.getPendingLightUpdates().decrementAndGet(); spongeChunk.getPendingLightUpdates().decrementAndGet();
@@ -296,7 +297,7 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld
return chunk.getBrightness(lightType, pos); return chunk.getBrightness(lightType, pos);
} }
private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) { private int getRawBlockLightAsync(EnumSkyBlock lightType, BlockPosition pos, Chunk currentChunk, List<Chunk> neighbors) {
final Chunk chunk = getLightChunk(pos, currentChunk, neighbors); final Chunk chunk = getLightChunk(pos, currentChunk, neighbors);
if (chunk == null || chunk.isUnloading()) { if (chunk == null || chunk.isUnloading()) {