Paper/Spigot-Server-Patches/0353-Configurable-Keep-Spawn-Loaded-range-per-world.patch
Aikar f7b4abb259
[Auto] Updated Upstream (Bukkit/CraftBukkit)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
15ba9ae7 SPIGOT-6357: Add World#getMinHeight

CraftBukkit Changes:
e9ad7cba9 SPIGOT-6357: Add World#getMinHeight
2021-03-28 04:42:30 -04:00

253 lines
13 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 13 Sep 2014 23:14:43 -0400
Subject: [PATCH] Configurable Keep Spawn Loaded range per world
This lets you disable it for some worlds and lower it for others.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 38d25a12c6a52d8a83214e2a0f43a218cf15ceac..ffe9b1a63d78925e1d77b9e730aef42fed6d58fa 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -440,4 +440,10 @@ public class PaperWorldConfig {
break;
}
}
+
+ public short keepLoadedRange;
+ private void keepLoadedRange() {
+ keepLoadedRange = (short) (getInt("keep-spawn-loaded-range", Math.min(spigotConfig.viewDistance, 10)) * 16);
+ log( "Keep Spawn Loaded Range: " + (keepLoadedRange/16));
+ }
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index b704401da2832601dd45d3c29e950cb52033a3fd..90eb5d8ed7698b5e19d38cec647c1bcbc15532f4 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -707,35 +707,36 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
// CraftBukkit start
public void loadSpawn(WorldLoadListener worldloadlistener, WorldServer worldserver) {
- if (!worldserver.getWorld().getKeepSpawnInMemory()) {
- return;
- }
+ ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper
// WorldServer worldserver = this.E();
this.forceTicks = true;
// CraftBukkit end
+ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.getDimensionKey().a());
BlockPosition blockposition = worldserver.getSpawn();
worldloadlistener.a(new ChunkCoordIntPair(blockposition));
- ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider();
+ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - move up
chunkproviderserver.getLightEngine().a(500);
this.nextTick = SystemUtils.getMonotonicMillis();
- chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE);
-
- while (chunkproviderserver.b() != 441) {
- // CraftBukkit start
- // this.nextTick = SystemUtils.getMonotonicMillis() + 10L;
- this.executeModerately();
- // CraftBukkit end
- }
-
+ // Paper start - configurable spawn reason
+ int radiusBlocks = worldserver.paperConfig.keepLoadedRange;
+ int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0);
+ int totalChunks = ((radiusChunks) * 2 + 1);
+ totalChunks *= totalChunks;
+ worldloadlistener.setChunkRadius(radiusBlocks / 16);
+
+ worldserver.addTicketsForSpawn(radiusBlocks, blockposition);
+ LOGGER.info("Loaded " + chunkproviderserver.b() + " spawn chunks for world " + worldserver.getWorld().getName()); // Paper
+ // Paper end
// CraftBukkit start
// this.nextTick = SystemUtils.getMonotonicMillis() + 10L;
this.executeModerately();
// Iterator iterator = this.worldServer.values().iterator();
+ }
if (true) {
WorldServer worldserver1 = worldserver;
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
index 44611304d5bf222900866319a02a333e0f56218d..16441006736abdea0120570557348be4919c82ad 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -67,6 +67,7 @@ import net.minecraft.network.protocol.game.PacketPlayOutWorldEvent;
import net.minecraft.network.protocol.game.PacketPlayOutWorldParticles;
import net.minecraft.resources.MinecraftKey;
import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.MCUtil;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ScoreboardServer;
import net.minecraft.server.level.progress.WorldLoadListener;
@@ -1672,12 +1673,88 @@ public class WorldServer extends World implements GeneratorAccessSeed {
return ((PersistentIdCounts) this.getMinecraftServer().E().getWorldPersistentData().a(PersistentIdCounts::new, "idcounts")).a();
}
+ // Paper start - helper function for configurable spawn radius
+ public void addTicketsForSpawn(int radiusInBlocks, BlockPosition spawn) {
+ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we add tickets
+ // with level 31 for the non-border spawn chunks
+ ChunkProviderServer chunkproviderserver = this.getChunkProvider();
+ int tickRadius = radiusInBlocks - 16;
+
+ // add ticking chunks
+ for (int x = -tickRadius; x <= tickRadius; x += 16) {
+ for (int z = -tickRadius; z <= tickRadius; z += 16) {
+ // radius of 2 will have the current chunk be level 31
+ chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, z)), 2, Unit.INSTANCE);
+ }
+ }
+
+ // add border chunks
+
+ // add border along x axis (including corner chunks)
+ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
+ // top
+ chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
+ // bottom
+ chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
+ }
+
+ // add border along z axis (excluding corner chunks)
+ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
+ // right
+ chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
+ // left
+ chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
+ }
+
+ MCUtil.getSpiralOutChunks(spawn, radiusInBlocks >> 4).forEach(pair -> {
+ getChunkProvider().getChunkAtMainThread(pair.x, pair.z);
+ });
+ }
+ public void removeTicketsForSpawn(int radiusInBlocks, BlockPosition spawn) {
+ // In order to respect vanilla behavior, which is ensuring everything but the spawn border can tick, we added tickets
+ // with level 31 for the non-border spawn chunks
+ ChunkProviderServer chunkproviderserver = this.getChunkProvider();
+ int tickRadius = radiusInBlocks - 16;
+
+ // remove ticking chunks
+ for (int x = -tickRadius; x <= tickRadius; x += 16) {
+ for (int z = -tickRadius; z <= tickRadius; z += 16) {
+ // radius of 2 will have the current chunk be level 31
+ chunkproviderserver.removeTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, z)), 2, Unit.INSTANCE);
+ }
+ }
+
+ // remove border chunks
+
+ // remove border along x axis (including corner chunks)
+ for (int x = -radiusInBlocks; x <= radiusInBlocks; x += 16) {
+ // top
+ chunkproviderserver.removeTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
+ // bottom
+ chunkproviderserver.removeTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(x, 0, -radiusInBlocks)), 1, Unit.INSTANCE); // level 32
+ }
+
+ // remove border along z axis (excluding corner chunks)
+ for (int z = -radiusInBlocks + 16; z < radiusInBlocks; z += 16) {
+ // right
+ chunkproviderserver.removeTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
+ // left
+ chunkproviderserver.removeTicket(TicketType.START, new ChunkCoordIntPair(spawn.add(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
+ }
+ }
+ // Paper end
+
public void a(BlockPosition blockposition, float f) {
- ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
+ // Paper - configurable spawn radius
+ BlockPosition prevSpawn = this.getSpawn();
+ //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
this.worldData.setSpawn(blockposition, f);
- this.getChunkProvider().removeTicket(TicketType.START, chunkcoordintpair, 11, Unit.INSTANCE);
- this.getChunkProvider().addTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE);
+ if (this.keepSpawnInMemory) {
+ // if this keepSpawnInMemory is false a plugin has already removed our tickets, do not re-add
+ this.removeTicketsForSpawn(this.paperConfig.keepLoadedRange, prevSpawn);
+ this.addTicketsForSpawn(this.paperConfig.keepLoadedRange, blockposition);
+ }
this.getMinecraftServer().getPlayerList().sendAll(new PacketPlayOutSpawnPosition(blockposition, f));
}
diff --git a/src/main/java/net/minecraft/server/level/progress/WorldLoadListener.java b/src/main/java/net/minecraft/server/level/progress/WorldLoadListener.java
index de011b5e3a5e751160b4d3b65b50f28e6c6a5f52..4d9c167a41366779dbfb5ded6ea0115ffbf06ed7 100644
--- a/src/main/java/net/minecraft/server/level/progress/WorldLoadListener.java
+++ b/src/main/java/net/minecraft/server/level/progress/WorldLoadListener.java
@@ -11,4 +11,6 @@ public interface WorldLoadListener {
void a(ChunkCoordIntPair chunkcoordintpair, @Nullable ChunkStatus chunkstatus);
void b();
+
+ void setChunkRadius(int radius); // Paper - allow changing chunk radius
}
diff --git a/src/main/java/net/minecraft/server/level/progress/WorldLoadListenerLogger.java b/src/main/java/net/minecraft/server/level/progress/WorldLoadListenerLogger.java
index 872d00de41533ab7f4b43874de6c1747022e2ac5..ca81664d884e80e5cb1eb376a2c2ef1e017f16c0 100644
--- a/src/main/java/net/minecraft/server/level/progress/WorldLoadListenerLogger.java
+++ b/src/main/java/net/minecraft/server/level/progress/WorldLoadListenerLogger.java
@@ -12,16 +12,24 @@ import org.apache.logging.log4j.Logger;
public class WorldLoadListenerLogger implements WorldLoadListener {
private static final Logger LOGGER = LogManager.getLogger();
- private final int b;
+ private int b; // Paper - remove final
private int c;
private long d;
private long e = Long.MAX_VALUE;
public WorldLoadListenerLogger(int i) {
- int j = i * 2 + 1;
+ // Paper start - Allow changing radius later for configurable spawn patch
+ this.setChunkRadius(i); // Move to method
+ }
+
+ @Override
+ public void setChunkRadius(int radius) {
+ // Paper - copied from above
+ int j = radius * 2 + 1;
this.b = j * j;
}
+ // Paper end
@Override
public void a(ChunkCoordIntPair chunkcoordintpair) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index d17d77dd9e059bafc3b59ac12f601f9d54226829..c19ac8c28a799bebf68f098171cefd0fc3ec3f0b 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1978,15 +1978,21 @@ public class CraftWorld implements World {
@Override
public void setKeepSpawnInMemory(boolean keepLoaded) {
+ // Paper start - Configurable spawn radius
+ if (keepLoaded == world.keepSpawnInMemory) {
+ // do nothing, nothing has changed
+ return;
+ }
world.keepSpawnInMemory = keepLoaded;
// Grab the worlds spawn chunk
- BlockPosition chunkcoordinates = this.world.getSpawn();
+ BlockPosition prevSpawn = this.world.getSpawn();
if (keepLoaded) {
- world.getChunkProvider().addTicket(TicketType.START, new ChunkCoordIntPair(chunkcoordinates), 11, Unit.INSTANCE);
+ world.addTicketsForSpawn(world.paperConfig.keepLoadedRange, prevSpawn);
} else {
- // TODO: doesn't work well if spawn changed....
- world.getChunkProvider().removeTicket(TicketType.START, new ChunkCoordIntPair(chunkcoordinates), 11, Unit.INSTANCE);
+ // TODO: doesn't work well if spawn changed.... // paper - resolved
+ world.removeTicketsForSpawn(world.paperConfig.keepLoadedRange, prevSpawn);
}
+ // Paper end
}
@Override