Remove chunk unload queue
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
package io.akarin.server.mixin.cps;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.spigotmc.SlackActivityAccountant;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import net.minecraft.server.Chunk;
|
||||||
|
import net.minecraft.server.ChunkProviderServer;
|
||||||
|
import net.minecraft.server.IChunkLoader;
|
||||||
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
|
@Mixin(value = ChunkProviderServer.class, remap = false)
|
||||||
|
public class MixinChunkProviderServer {
|
||||||
|
@Shadow @Final public WorldServer world;
|
||||||
|
@Shadow public Long2ObjectOpenHashMap<Chunk> chunks;
|
||||||
|
|
||||||
|
public int pendingUnloadChunks; // For keeping unload target-size features
|
||||||
|
|
||||||
|
public void unload(Chunk chunk) {
|
||||||
|
if (this.world.worldProvider.c(chunk.locX, chunk.locZ)) {
|
||||||
|
// Akarin - avoid using the queue and simply check the unloaded flag during unloads
|
||||||
|
// this.unloadQueue.add(Long.valueOf(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)));
|
||||||
|
pendingUnloadChunks++;
|
||||||
|
chunk.setShouldUnload(true); // PAIL: shouldUnload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Shadow public boolean unloadChunk(Chunk chunk, boolean save) { return true; }
|
||||||
|
@Shadow @Final private IChunkLoader chunkLoader;
|
||||||
|
@Shadow @Final private static double UNLOAD_QUEUE_RESIZE_FACTOR;
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
for (int i = 0; i < chunks.size() && pendingUnloadChunks > targetSize; i++) { // CraftBukkit removes unload logic to its method, we must check index
|
||||||
|
Chunk chunk = it.next();
|
||||||
|
|
||||||
|
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--;
|
||||||
|
|
||||||
|
if (activityAccountant.activityTimeIsExhausted()) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activityAccountant.endActivity();
|
||||||
|
this.chunkLoader.b(); // PAIL: chunkTick
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Overwrite
|
||||||
|
public String getName() {
|
||||||
|
return "ServerChunkCache: " + chunks.size(); // Akarin - remove unload queue
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package io.akarin.server.mixin.cps;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.spongepowered.asm.lib.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "processChunkGC()V", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "java/util/Set.contains(Ljava/lang/Object;)Z",
|
||||||
|
opcode = Opcodes.INVOKEINTERFACE
|
||||||
|
))
|
||||||
|
public boolean checkUnloading(Set<Long> set, Object chunkHash) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "regenerateChunk", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "java/util/Set.remove(Ljava/lang/Object;)Z",
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,9 @@
|
|||||||
"core.MixinMinecraftServer",
|
"core.MixinMinecraftServer",
|
||||||
"core.MixinChunkIOExecutor",
|
"core.MixinChunkIOExecutor",
|
||||||
|
|
||||||
|
"cps.MixinCraftWorld",
|
||||||
|
"cps.MixinChunkProviderServer",
|
||||||
|
|
||||||
"nsc.MixinPlayerConnection",
|
"nsc.MixinPlayerConnection",
|
||||||
"nsc.OptimisticNetworkManager",
|
"nsc.OptimisticNetworkManager",
|
||||||
"nsc.NonblockingServerConnection",
|
"nsc.NonblockingServerConnection",
|
||||||
|
|||||||
Reference in New Issue
Block a user