aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch')
-rw-r--r--patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch252
1 files changed, 252 insertions, 0 deletions
diff --git a/patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch
new file mode 100644
index 0000000000..f0e25d5b10
--- /dev/null
+++ b/patches/server/0329-Configurable-Keep-Spawn-Loaded-range-per-world.patch
@@ -0,0 +1,252 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+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 eb44aef0aecf65f5c1b19f42bf85a3a263965a7c..5589ee42959e3665dd5df9049fe108b6f6629608 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+@@ -56,6 +56,12 @@ public class PaperWorldConfig {
+ }
+ }
+
++ 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));
++ }
++
+ private boolean getBoolean(String path, boolean def) {
+ config.addDefault("world-settings.default." + path, def);
+ return config.getBoolean("world-settings." + worldName + "." + path, config.getBoolean("world-settings.default." + path));
+diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
+index bd8e654c1580a0ac7dd411b9f1dcad4a20d1d3e5..7576047ea9695434ca06ca8fefde0dce68980be8 100644
+--- a/src/main/java/net/minecraft/server/MinecraftServer.java
++++ b/src/main/java/net/minecraft/server/MinecraftServer.java
+@@ -760,35 +760,36 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+
+ // CraftBukkit start
+ public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) {
+- if (!worldserver.getWorld().getKeepSpawnInMemory()) {
+- return;
+- }
++ ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper
+
+ // WorldServer worldserver = this.overworld();
+ this.forceTicks = true;
+ // CraftBukkit end
++ if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper
+
+ MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location());
+ BlockPos blockposition = worldserver.getSharedSpawnPos();
+
+ worldloadlistener.updateSpawnPos(new ChunkPos(blockposition));
+- ServerChunkCache chunkproviderserver = worldserver.getChunkSource();
++ //ChunkProviderServer chunkproviderserver = worldserver.getChunkProvider(); // Paper - move up
+
+ chunkproviderserver.getLightEngine().setTaskPerBatch(500);
+ this.nextTickTime = Util.getMillis();
+- chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE);
+-
+- while (chunkproviderserver.getTickingGenerated() != 441) {
+- // CraftBukkit start
+- // this.nextTickTime = SystemUtils.getMillis() + 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);
++ // Paper end
+
+ // CraftBukkit start
+ // this.nextTickTime = SystemUtils.getMillis() + 10L;
+ this.executeModerately();
+ // Iterator iterator = this.levels.values().iterator();
++ }
+
+ if (true) {
+ ServerLevel worldserver1 = worldserver;
+@@ -811,7 +812,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+ // this.nextTickTime = SystemUtils.getMillis() + 10L;
+ this.executeModerately();
+ // CraftBukkit end
+- worldloadlistener.stop();
++ if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper
+ chunkproviderserver.getLightEngine().setTaskPerBatch(5);
+ // CraftBukkit start
+ // this.updateMobSpawningFlags();
+diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
+index 2950ad995f322570cd647d3217f340327cc3e7c8..fef3846a978dcba95c5dbe5c528ac20cb4f56178 100644
+--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
+@@ -60,6 +60,7 @@ import net.minecraft.network.protocol.game.ClientboundSoundEntityPacket;
+ import net.minecraft.network.protocol.game.ClientboundSoundPacket;
+ import net.minecraft.network.protocol.game.DebugPackets;
+ import net.minecraft.resources.ResourceKey;
++import net.minecraft.server.MCUtil;
+ import net.minecraft.server.MinecraftServer;
+ import net.minecraft.server.ServerScoreboard;
+ import net.minecraft.server.level.progress.ChunkProgressListener;
+@@ -1606,12 +1607,84 @@ public class ServerLevel extends Level implements WorldGenLevel {
+ return ((MapIndex) this.getServer().overworld().getDataStorage().computeIfAbsent(MapIndex::load, MapIndex::new, "idcounts")).getFreeAuxValueForMap();
+ }
+
++ // Paper start - helper function for configurable spawn radius
++ public void addTicketsForSpawn(int radiusInBlocks, BlockPos 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
++ ServerChunkCache chunkproviderserver = this.getChunkSource();
++ 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.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(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.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ // bottom
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(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.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ // left
++ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ }
++ }
++ public void removeTicketsForSpawn(int radiusInBlocks, BlockPos 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
++ ServerChunkCache chunkproviderserver = this.getChunkSource();
++ 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.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(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.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(x, 0, radiusInBlocks)), 1, Unit.INSTANCE); // level 32
++ // bottom
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(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.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ // left
++ chunkproviderserver.removeRegionTicket(TicketType.START, new ChunkPos(spawn.offset(-radiusInBlocks, 0, z)), 1, Unit.INSTANCE); // level 32
++ }
++ }
++ // Paper end
++
+ public void setDefaultSpawnPos(BlockPos pos, float angle) {
+- ChunkPos chunkcoordintpair = new ChunkPos(new BlockPos(this.levelData.getXSpawn(), 0, this.levelData.getZSpawn()));
++ // Paper - configurable spawn radius
++ BlockPos prevSpawn = this.getSharedSpawnPos();
++ //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
+
+ this.levelData.setSpawn(pos, angle);
+- this.getChunkSource().removeRegionTicket(TicketType.START, chunkcoordintpair, 11, Unit.INSTANCE);
+- this.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(pos), 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, pos);
++ }
+ this.getServer().getPlayerList().broadcastAll(new ClientboundSetDefaultSpawnPositionPacket(pos, angle));
+ }
+
+diff --git a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
+index 1b565b2809c2d367e21971c5154f35c9763995e6..b0f899835ded29aff108d1674bf4a1a6c89693db 100644
+--- a/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
++++ b/src/main/java/net/minecraft/server/level/progress/ChunkProgressListener.java
+@@ -12,4 +12,6 @@ public interface ChunkProgressListener {
+ void start();
+
+ void stop();
++
++ void setChunkRadius(int radius); // Paper - allow changing chunk radius
+ }
+diff --git a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
+index 4185e6bcf9b2bb65b2a0fa5fcbeb5684615169a7..dbc29442f2b2ad3ea451910f4944e90114a317c7 100644
+--- a/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
++++ b/src/main/java/net/minecraft/server/level/progress/LoggerChunkProgressListener.java
+@@ -11,12 +11,19 @@ import org.apache.logging.log4j.Logger;
+
+ public class LoggerChunkProgressListener implements ChunkProgressListener {
+ private static final Logger LOGGER = LogManager.getLogger();
+- private final int maxCount;
++ private int maxCount; // Paper - remove final
+ private int count;
+ private long startTime;
+ private long nextTickTime = Long.MAX_VALUE;
+
+ public LoggerChunkProgressListener(int radius) {
++ // Paper start - Allow changing radius later for configurable spawn patch
++ this.setChunkRadius(radius); // Move to method
++ }
++
++ @Override
++ public void setChunkRadius(int radius) {
++ // Paper end
+ int i = radius * 2 + 1;
+ this.maxCount = i * i;
+ }
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+index 29509d3ae956fd4da2bf12c6a352ab115fc75f5c..255616aa45b06487c67aa6011dbe29e18d82bc68 100644
+--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+@@ -1340,15 +1340,21 @@ public class CraftWorld extends CraftRegionAccessor implements World {
+
+ @Override
+ public void setKeepSpawnInMemory(boolean keepLoaded) {
+- world.keepSpawnInMemory = keepLoaded;
++ // Paper start - Configurable spawn radius
++ if (keepLoaded == world.keepSpawnInMemory) {
++ // do nothing, nothing has changed
++ return;
++ }
++ this.world.keepSpawnInMemory = keepLoaded;
+ // Grab the worlds spawn chunk
+ BlockPos chunkcoordinates = this.world.getSharedSpawnPos();
+ if (keepLoaded) {
+- this.world.getChunkSource().addRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
++ this.world.addTicketsForSpawn(this.world.paperConfig.keepLoadedRange, chunkcoordinates);
+ } else {
+- // TODO: doesn't work well if spawn changed....
+- this.world.getChunkSource().removeRegionTicket(TicketType.START, new ChunkPos(chunkcoordinates), 11, Unit.INSTANCE);
++ // TODO: doesn't work well if spawn changed.... // Paper - resolved
++ this.world.removeTicketsForSpawn(this.world.paperConfig.keepLoadedRange, chunkcoordinates);
+ }
++ // Paper end
+ }
+
+ @Override