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 a9a3dbbe7608d1f0dc122fe8d49928e7e3fa1438..e9c03546c42657dd5f5d4c6f71bd7e0cc7e2cb15 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -434,4 +434,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 44991803a489a42842f79ce51bdd53a73ef35d71..7d9a3375d289deccdfa0f4caa8a2088550c560aa 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -597,35 +597,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/WorldLoadListener.java b/src/main/java/net/minecraft/server/WorldLoadListener.java index d6762d3853b55b639047f455351150a1cbc9399a..7b6f5b2da0a76661a0e047ee7002aa07cdd4a8b1 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 3868572aed50c8bffd93727a139a3fbb8dc19688..ae77805f71c6c574d92f39c51b1e48f2138e9ab6 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 de2bdd55213613f439cd797bfe01986c8851eaa4..644167d400e0f4af142f0afe6a11cae4ac591ddf 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -1552,12 +1552,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/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 2dd749a375aaa2e89ffdafe986ef331234086929..7287f595c89e0548252a2c39464d4a06d7f71bb7 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1954,15 +1954,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