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.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user