mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-01 17:01:56 +01:00
fd5c98a9ef
Removes synchronization from sending packets Makes normal packet sends no longer need to be wrapped and queued like it use to work. Adds more packet queue immunities on top of keep alive to let the following scenarios go out without delay: - Keep Alive - Chat - Kick - All of the packets during the Player Joined World event Hoping that latter one helps join timeout issues more too for slow connections. Removes processing packet queue off of main thread - for the few cases where it is allowed, order is not necessary nor should it even be happening concurrently in first place (handshaking/login/status) Ensures packets sent asynchronously are dispatched on main thread This helps ensure safety for ProtocolLib as packet listeners are commonly accessing world state. This will allow you to schedule a packet to be sent async, but itll be dispatched sync for packet listeners to process. This should solve some deadlock risks This may provide a decent performance improvement because thread synchronization incurs a cache reset so by avoiding ever entering a synchronized block, we get to avoid that, and packet sending is a really hot activity.
231 lines
No EOL
11 KiB
Diff
231 lines
No EOL
11 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 572679e4d1c..071e5e7f729 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -0,0 +0,0 @@ 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 45882ee30f5..0ee1d8e4869 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -0,0 +0,0 @@ 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();
|
|
|
|
@@ -0,0 +0,0 @@ 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);
|
|
}
|
|
+ // 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 d6762d3853b..7b6f5b2da0a 100644
|
|
--- a/src/main/java/net/minecraft/server/WorldLoadListener.java
|
|
+++ b/src/main/java/net/minecraft/server/WorldLoadListener.java
|
|
@@ -0,0 +0,0 @@ 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 3868572aed5..ae77805f71c 100644
|
|
--- a/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
|
|
+++ b/src/main/java/net/minecraft/server/WorldLoadListenerLogger.java
|
|
@@ -0,0 +0,0 @@ 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 081df240f30..ce506e0e129 100644
|
|
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
|
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
|
@@ -0,0 +0,0 @@ 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
|
|
+ }
|
|
+
|
|
+ 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
|
|
+
|
|
@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 5ea7b0b25ae..8f8c18c5a4f 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -0,0 +0,0 @@ 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
|
|
--
|