Paper/Spigot-Server-Patches/0376-Configurable-Keep-Spawn-Loaded-range-per-world.patch
Shane Freeder f8fd607e04
Updated Upstream (Bukkit/CraftBukkit/Spigot)
Upstream has released updates that appears 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:
bbfd13dd Hyperlink 'Events' in raid event package documentation
b2095bed SPIGOT-5413: Add TrustedPlayer API for foxes
1bf1f3f4 Block trace methods do not require hash sets
abf0cfdc Javadoc improvements per checkstyle
c4a2b425 Add TimeSkipEvent

CraftBukkit Changes:
817116de SPIGOT-5413: Add TrustedPlayer API for foxes
062680a8 SPIGOT-5467: Calm down bees that cannot exit hive
75fac431 SPIGOT-5472: Spurious warning when using clone command on tile entities
85106731 SPIGOT-5471: Allow empty title/author for books
2d9db47f Add TimeSkipEvent
384225c2 Add thread name to TerminalConsoleWriterThread

Spigot Changes:
05bb8bcf Postpone stopping the watchdog until the server is completely stopped
18e2b9be Add package-info.java for Spigot APIs
2019-12-23 02:37:47 +00:00

242 lines
12 KiB
Diff

From 32d9af31e6fe690da40e488379a36f1510796959 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 2b2c82d5e..778de4630 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -479,4 +479,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 fd7526137..105ac1358 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -585,6 +585,14 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
this.forceTicks = true;
// 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);
+ // Paper end
+
MinecraftServer.LOGGER.info("Preparing start region for dimension '{}'/{}", worldserver.getWorldData().getName(), DimensionManager.a(worldserver.worldProvider.getDimensionManager().getType())); // CraftBukkit
BlockPosition blockposition = worldserver.getSpawn();
@@ -593,14 +601,24 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
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 radius
+ if (worldserver.keepSpawnInMemory) {
+ worldserver.addTicketsForSpawn(radiusBlocks, blockposition);
+
+ // we use a getChunk loop since we don't need to worry about what some plugin does to keepSpawnInMemory
+ // or the spawn radius while we are loading
+ // just keep in mind too that executeModerately will handle player network queue (i.e commands)
+ int centerX = blockposition.getX() >> 4;
+ int centerZ = blockposition.getZ() >> 4;
+ radiusChunks += 2; // we need to load radius +2 to get the chunks in ticking level
+ for (int xoff = -radiusChunks; xoff <= radiusChunks; ++xoff) {
+ for (int zoff = -radiusChunks; zoff <= radiusChunks; ++zoff) {
+ worldserver.getChunkAt(centerX + xoff, centerZ + zoff);
+ }
+ }
}
+ // Paper end
+ LOGGER.info("Loaded " + chunkproviderserver.b() + " spawn chunks for world " + worldserver.getWorldData().getName()); // Paper
// CraftBukkit start
// this.nextTick = SystemUtils.getMonotonicMillis() + 10L;
diff --git a/src/main/java/net/minecraft/server/WorldLoadListener.java b/src/main/java/net/minecraft/server/WorldLoadListener.java
index d6762d385..7b6f5b2da 100644
--- a/src/main/java/net/minecraft/server/WorldLoadListener.java
+++ b/src/main/java/net/minecraft/server/WorldLoadListener.java
@@ -9,4 +9,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/WorldLoadListenerLogger.java b/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
index 3868572ae..ae77805f7 100644
--- a/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
+++ b/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
@@ -7,16 +7,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/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index c4fabc477..8b3ea6544 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1566,13 +1566,85 @@ public class WorldServer extends World {
return ((PersistentIdCounts) this.getMinecraftServer().getWorldServer(DimensionManager.OVERWORLD).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
+ }
+ }
+ 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
+
@Override
public void a_(BlockPosition blockposition) {
- ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.b(), 0, this.worldData.d()));
+ // Paper - configurable spawn radius
+ BlockPosition prevSpawn = this.getSpawn();
super.a_(blockposition);
- 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);
+ }
+ // Paper end
}
public LongSet getForceLoadedChunks() {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index bc968fc7e..0850d78e2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1914,15 +1914,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
--
2.24.1