Fixes chunk unloading
This commit is contained in:
@@ -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() && 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<Chunk> chunks, Object chunkHash) {
|
||||
private Object remove(Long2ObjectOpenHashMap<Chunk> chunks, long chunkHash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Chunk> neighbors) {
|
||||
final Chunk chunk = getLightChunk(pos, currentChunk, neighbors);
|
||||
if (chunk == null || chunk.isUnloading()) {
|
||||
|
||||
Reference in New Issue
Block a user