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.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<Chunk> 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<Chunk> it = chunks.values().iterator();
while (it.hasNext()) {
activityAccountant.startActivity(0.5);
while (it.hasNext() && pendingUnloadChunks > targetSize) {
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<Chunk> chunks, Object chunkHash) {
private Object remove(Long2ObjectOpenHashMap<Chunk> chunks, long chunkHash) {
return null;
}

View File

@@ -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<Long> 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;
}
}

View File

@@ -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);

View File

@@ -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();
}
}
}