2020-05-06 11:48:49 +02:00
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
2019-05-24 05:12:57 +02:00
|
|
|
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
|
2020-06-28 10:35:41 +02:00
|
|
|
index 6e29e3294d0661cc35d53b4201d980a2db4f5c93..6e1756eb90b6237100612527f69c995246d53ed1 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
2020-06-28 10:35:41 +02:00
|
|
|
@@ -444,4 +444,10 @@ public class PaperWorldConfig {
|
2019-05-24 05:12:57 +02:00
|
|
|
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
|
2020-06-30 07:20:29 +02:00
|
|
|
index b9e047643e1c3f84f26d936fcb067f607018ef34..d6a3c51826ac82fd46b8f6c98be7bf405ffa3f38 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
2020-06-26 18:20:03 +02:00
|
|
|
@@ -607,6 +607,14 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
2019-05-24 05:12:57 +02:00
|
|
|
this.forceTicks = true;
|
|
|
|
// CraftBukkit end
|
|
|
|
|
|
|
|
+ // Paper start - configurable spawn reason
|
|
|
|
+ int radiusBlocks = worldserver.paperConfig.keepLoadedRange;
|
2019-09-30 03:23:09 +02:00
|
|
|
+ int radiusChunks = radiusBlocks / 16 + ((radiusBlocks & 15) != 0 ? 1 : 0);
|
|
|
|
+ int totalChunks = ((radiusChunks) * 2 + 1);
|
2019-05-24 05:12:57 +02:00
|
|
|
+ totalChunks *= totalChunks;
|
2019-09-30 03:23:09 +02:00
|
|
|
+ worldloadlistener.setChunkRadius(radiusBlocks / 16);
|
2019-05-24 05:12:57 +02:00
|
|
|
+ // Paper end
|
|
|
|
+
|
2020-06-25 16:09:55 +02:00
|
|
|
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.getDimensionKey().a());
|
2019-05-24 05:12:57 +02:00
|
|
|
BlockPosition blockposition = worldserver.getSpawn();
|
|
|
|
|
2020-06-26 18:20:03 +02:00
|
|
|
@@ -615,14 +623,12 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
2019-05-24 05:12:57 +02:00
|
|
|
|
|
|
|
chunkproviderserver.getLightEngine().a(500);
|
|
|
|
this.nextTick = SystemUtils.getMonotonicMillis();
|
|
|
|
- chunkproviderserver.addTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE);
|
2019-09-30 03:23:09 +02:00
|
|
|
-
|
|
|
|
- while (chunkproviderserver.b() != 441) {
|
|
|
|
- // CraftBukkit start
|
|
|
|
- // this.nextTick = SystemUtils.getMonotonicMillis() + 10L;
|
|
|
|
- this.executeModerately();
|
|
|
|
- // CraftBukkit end
|
2019-05-24 05:12:57 +02:00
|
|
|
+ // Paper start - Configurable spawn radius
|
|
|
|
+ if (worldserver.keepSpawnInMemory) {
|
|
|
|
+ worldserver.addTicketsForSpawn(radiusBlocks, blockposition);
|
|
|
|
}
|
2019-09-30 03:23:09 +02:00
|
|
|
+ // Paper end
|
2020-06-26 08:29:44 +02:00
|
|
|
+ LOGGER.info("Loaded " + chunkproviderserver.b() + " spawn chunks for world " + worldserver.getWorld().getName()); // Paper
|
2019-05-24 05:12:57 +02:00
|
|
|
|
|
|
|
// 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
|
2020-05-06 11:48:49 +02:00
|
|
|
index d6762d3853b55b639047f455351150a1cbc9399a..7b6f5b2da0a76661a0e047ee7002aa07cdd4a8b1 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- 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
|
2020-05-06 11:48:49 +02:00
|
|
|
index 3868572aed50c8bffd93727a139a3fbb8dc19688..ae77805f71c6c574d92f39c51b1e48f2138e9ab6 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- 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
|
2020-07-14 12:58:55 +02:00
|
|
|
index d1580a77383a4ad5a45aca57f29258869b52b86c..45959064c310997d26c5637a0e5cb61775c406c9 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
2020-07-14 12:58:55 +02:00
|
|
|
@@ -1499,12 +1499,88 @@ public class WorldServer extends World implements GeneratorAccessSeed {
|
2020-06-25 16:09:55 +02:00
|
|
|
return ((PersistentIdCounts) this.getMinecraftServer().D().getWorldPersistentData().a(PersistentIdCounts::new, "idcounts")).a();
|
2019-05-24 05:12:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
+ // Paper start - helper function for configurable spawn radius
|
|
|
|
+ public void addTicketsForSpawn(int radiusInBlocks, BlockPosition spawn) {
|
2019-06-14 04:27:40 +02:00
|
|
|
+ // 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
|
2019-05-24 05:12:57 +02:00
|
|
|
+ ChunkProviderServer chunkproviderserver = this.getChunkProvider();
|
2019-06-14 04:27:40 +02:00
|
|
|
+ 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);
|
2019-05-24 05:12:57 +02:00
|
|
|
+ }
|
|
|
|
+ }
|
2019-06-14 04:27:40 +02:00
|
|
|
+
|
|
|
|
+ // 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
|
|
|
|
+ }
|
2020-04-19 12:01:07 +02:00
|
|
|
+
|
|
|
|
+ MCUtil.getSpiralOutChunks(spawn, radiusInBlocks >> 4).forEach(pair -> {
|
|
|
|
+ getChunkProvider().getChunkAtMainThread(pair.x, pair.z);
|
|
|
|
+ });
|
2019-05-24 05:12:57 +02:00
|
|
|
+ }
|
|
|
|
+ public void removeTicketsForSpawn(int radiusInBlocks, BlockPosition spawn) {
|
2019-06-14 04:27:40 +02:00
|
|
|
+ // 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
|
2019-05-24 05:12:57 +02:00
|
|
|
+ ChunkProviderServer chunkproviderserver = this.getChunkProvider();
|
2019-06-14 04:27:40 +02:00
|
|
|
+ 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);
|
2019-05-24 05:12:57 +02:00
|
|
|
+ }
|
|
|
|
+ }
|
2019-06-14 04:27:40 +02:00
|
|
|
+
|
|
|
|
+ // 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
|
|
|
|
+ }
|
2019-05-24 05:12:57 +02:00
|
|
|
+ }
|
|
|
|
+ // Paper end
|
|
|
|
+
|
|
|
|
public void a_(BlockPosition blockposition) {
|
2020-06-25 16:09:55 +02:00
|
|
|
- ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
|
2019-05-24 05:12:57 +02:00
|
|
|
+ // Paper - configurable spawn radius
|
|
|
|
+ BlockPosition prevSpawn = this.getSpawn();
|
2020-06-25 16:09:55 +02:00
|
|
|
+ //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
|
2019-05-24 05:12:57 +02:00
|
|
|
|
2020-06-25 16:09:55 +02:00
|
|
|
this.worldData.setSpawn(blockposition);
|
2019-05-24 05:12:57 +02:00
|
|
|
- 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);
|
|
|
|
+ }
|
2020-06-25 16:09:55 +02:00
|
|
|
this.getMinecraftServer().getPlayerList().sendAll(new PacketPlayOutSpawnPosition(blockposition));
|
2019-05-24 05:12:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
2020-07-14 12:58:55 +02:00
|
|
|
index 48805c32aabe453e0a860168b79ea9026fa848b1..b5621b8456fbd3c5e94a9b9ec9b4be0068962674 100644
|
2019-05-24 05:12:57 +02:00
|
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
2020-07-01 02:07:16 +02:00
|
|
|
@@ -1949,15 +1949,21 @@ public class CraftWorld implements World {
|
2019-05-24 05:12:57 +02:00
|
|
|
|
|
|
|
@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
|