diff --git a/build.gradle.kts b/build.gradle.kts index 9e49b28..64089e8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { java `maven-publish` id("com.github.johnrengelman.shadow") version "8.1.1" apply false - id("io.papermc.paperweight.patcher") version "1.5.5" + id("io.papermc.paperweight.patcher") version "1.5.6" } val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" diff --git a/gradle.properties b/gradle.properties index 3d0fb66..2f549c8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ group=dev.folia -version=1.20.1-R0.1-SNAPSHOT -mcVersion=1.20.1 -paperRef=fb06829845db10be0405966f874a16f135f73229 +version=1.20.2-R0.1-SNAPSHOT +mcVersion=1.20.2 +paperRef=fe54a13b1301312304d9c1e46ad91b039657120b org.gradle.caching=true org.gradle.parallel=true diff --git a/patches/server/0001-Build-changes.patch b/patches/server/0001-Build-changes.patch index 7227a94..87356b6 100644 --- a/patches/server/0001-Build-changes.patch +++ b/patches/server/0001-Build-changes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Build changes diff --git a/build.gradle.kts b/build.gradle.kts -index fb98936bb8a5488db75d676c5bcb4060597fbbf8..9ee90bc753e65f9dd532f28ec75cc16bf16486c8 100644 +index 683159586641dd9aa42ae96fa51602469755723f..521ff85fcf10fc85fe706d6fa3778e0569551829 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,8 +13,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { @@ -32,7 +32,7 @@ index fb98936bb8a5488db75d676c5bcb4060597fbbf8..9ee90bc753e65f9dd532f28ec75cc16b "Implementation-Vendor" to date, // Paper "Specification-Title" to "Bukkit", "Specification-Version" to project.version, -@@ -149,7 +153,7 @@ fun TaskContainer.registerRunTask( +@@ -156,7 +160,7 @@ fun TaskContainer.registerRunTask( name: String, block: JavaExec.() -> Unit ): TaskProvider = register(name) { @@ -93,10 +93,10 @@ index 9d687da5bdf398bb3f6c84cdf1249a7213d09f2e..e2f704c115fd6e00960bb56bb0779f11 ).openBufferedStream()) { JsonObject json = new Gson().fromJson(reader, JsonObject.class); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 67ee3a4ca8a6cdeb275653d492a1fea8037c51fb..211408450ab4bf714860a52a9deff63e75ec20d1 100644 +index 97745f0bab8d82d397c6c2a5775aed92bca0a034..a17160766eb15e8d11ddcce23747f8ab1923b676 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1692,7 +1692,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { diff --git a/patches/server/0003-Threaded-Regions.patch b/patches/server/0003-Threaded-Regions.patch index 01dd85f..d24012e 100644 --- a/patches/server/0003-Threaded-Regions.patch +++ b/patches/server/0003-Threaded-Regions.patch @@ -6,35 +6,6 @@ Subject: [PATCH] Threaded Regions See https://docs.papermc.io/folia/reference/overview and https://docs.papermc.io/folia/reference/region-logic -diff --git a/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java b/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java -index f4415f782b32fed25da98e44b172f717c4d46e34..ba7c24b3627a1827721d2462add15fdd4adbed90 100644 ---- a/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java -+++ b/src/main/java/ca/spottedleaf/concurrentutil/collection/MultiThreadedQueue.java -@@ -392,6 +392,24 @@ public class MultiThreadedQueue implements Queue { - } - } - -+ /** -+ * Returns whether this queue is currently add-blocked. That is, whether {@link #add(Object)} and friends will return {@code false}. -+ */ -+ public boolean isAddBlocked() { -+ for (LinkedNode tail = this.getTailOpaque();;) { -+ LinkedNode next = tail.getNextVolatile(); -+ if (next == null) { -+ return false; -+ } -+ -+ if (next == tail) { -+ return true; -+ } -+ -+ tail = next; -+ } -+ } -+ - /** - * Atomically removes the head from this queue if it exists, otherwise prevents additions to this queue if no - * head is removed. diff --git a/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRInt2IntHashTable.java b/src/main/java/ca/spottedleaf/concurrentutil/map/SWMRInt2IntHashTable.java new file mode 100644 index 0000000000000000000000000000000000000000..7869cc177c95e26dd9e1d3db5b50e996956edb24 @@ -1881,10 +1852,10 @@ index 22a2547810d0c029f29685faddf7ac21cde2df0b..e36b4053eb2676e934b8c9c401bf58cf // The variable 'k' holds the maximum redstone power value of any adjacent blocks. // If 'k' has the highest level of all neighbors, then the power level of this diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -index 774fb97912f766589f3548f659618ad554e0503f..c44023a2f825507625a244ea8dfaa6073ed36806 100644 +index e4fd372a1d585887287253a02531cd192929377b..772e3a864e0e70288a1c010d8bbb809d34d16a41 100644 --- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java +++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -@@ -98,7 +98,7 @@ public final class ChatProcessor { +@@ -100,7 +100,7 @@ public final class ChatProcessor { final CraftPlayer player = this.player.getBukkitEntity(); final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server)); this.post(ae); @@ -1893,7 +1864,7 @@ index 774fb97912f766589f3548f659618ad554e0503f..c44023a2f825507625a244ea8dfaa607 final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients()); se.setCancelled(ae.isCancelled()); // propagate cancelled state this.queueIfAsyncOrRunImmediately(new Waitable() { -@@ -178,7 +178,7 @@ public final class ChatProcessor { +@@ -180,7 +180,7 @@ public final class ChatProcessor { ae.setCancelled(cancelled); // propagate cancelled state this.post(ae); final boolean listenersOnSyncEvent = canYouHearMe(ChatEvent.getHandlerList()); @@ -1962,12 +1933,12 @@ index 23432eea862c6df716d7726a32da3a0612a3fb77..f59e8bb72c5233f26a8a0d506ac64bb3 } } diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -index fccb8d7a99bef076838ebefa233f2f00a1364c30..e822f308315a955d00dcbedfc1b54d22b569c31e 100644 +index 95e5073a68e4dd38b70e8268daf2160922c3a12f..19349637e4a38e697debe6d18ab8b759ede0359e 100644 --- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java @@ -92,6 +92,9 @@ public final class ChunkSystem { for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { - chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); + chunkMap.regionManagers.get(index).addChunk(holder.getPos().x, holder.getPos().z); } + // Folia start - threaded regions + level.regioniser.addChunk(holder.pos.x, holder.pos.z); @@ -1975,9 +1946,9 @@ index fccb8d7a99bef076838ebefa233f2f00a1364c30..e822f308315a955d00dcbedfc1b54d22 } public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -@@ -99,30 +102,34 @@ public final class ChunkSystem { +@@ -99,34 +102,39 @@ public final class ChunkSystem { for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { - chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); + chunkMap.regionManagers.get(index).removeChunk(holder.getPos().x, holder.getPos().z); } + // Folia start - threaded regions + level.regioniser.removeChunk(holder.pos.x, holder.pos.z); @@ -1986,40 +1957,52 @@ index fccb8d7a99bef076838ebefa233f2f00a1364c30..e822f308315a955d00dcbedfc1b54d22 public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { chunk.playerChunk = holder; + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.FULL; + chunk.level.getCurrentWorldData().addChunk(chunk); // Folia - region threading } public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -- + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.INACCESSIBLE; + chunk.level.getCurrentWorldData().removeChunk(chunk); // Folia - region threading } public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { - chunk.level.getChunkSource().tickingChunks.add(chunk); -+ // Folia - region threading ++ chunk.level.getCurrentWorldData().addTickingChunk(chunk); // Folia - region threading + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.BLOCK_TICKING; } public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { - chunk.level.getChunkSource().tickingChunks.remove(chunk); -+ // Folia - region threading ++ chunk.level.getCurrentWorldData().removeTickingChunk(chunk); // Folia - region threading + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.FULL; } public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - chunk.level.getChunkSource().entityTickingChunks.add(chunk); + chunk.level.getCurrentWorldData().addEntityTickingChunk(chunk); // Folia - region threading + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.ENTITY_TICKING; } public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - chunk.level.getChunkSource().entityTickingChunks.remove(chunk); + chunk.level.getCurrentWorldData().removeEntityTickingChunk(chunk); // Folia - region threading + chunk.chunkStatus = net.minecraft.server.level.FullChunkStatus.BLOCK_TICKING; } - public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -index 924539d4ac50c70178ba220424ffacd6ff277c8b..7b664f32868028758d0c6ee1eaa82efcd83661d2 100644 +index 1b090f1e79b996e52097afc49c1cec85936653e6..07abf5a326cc7aa8a449b74bd7ac8a43b98528c0 100644 --- a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java +++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -155,7 +155,7 @@ public class RegionizedPlayerChunkLoader { +@@ -141,6 +141,7 @@ public class RegionizedPlayerChunkLoader { + public void updatePlayer(final ServerPlayer player) { + final PlayerChunkLoaderData loader = player.chunkLoader; + if (loader != null) { ++ player.serverLevel().chunkSource.chunkMap.getNearbyPlayers().tickPlayer(player); // Folia - region threading + loader.update(); + } + } +@@ -154,7 +155,7 @@ public class RegionizedPlayerChunkLoader { final PlayerChunkLoaderData loader = player.chunkLoader; if (loader == null) { @@ -2028,7 +2011,7 @@ index 924539d4ac50c70178ba220424ffacd6ff277c8b..7b664f32868028758d0c6ee1eaa82efc } loader.remove(); -@@ -234,7 +234,7 @@ public class RegionizedPlayerChunkLoader { +@@ -233,7 +234,7 @@ public class RegionizedPlayerChunkLoader { public void tick() { TickThread.ensureTickThread("Cannot tick player chunk loader async"); long currTime = System.nanoTime(); @@ -2038,10 +2021,10 @@ index 924539d4ac50c70178ba220424ffacd6ff277c8b..7b664f32868028758d0c6ee1eaa82efc if (loader == null || loader.world != this.world) { // not our problem anymore diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5bc59e0864 100644 +index c4d1dbbd39ba0cdc9176ffa6d350d2aa50380211..20a42a13adaf97aa6ff668a1f2c9e5264f474716 100644 --- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -@@ -189,7 +189,12 @@ public final class EntityLookup implements LevelEntityGetter { +@@ -191,7 +191,12 @@ public final class EntityLookup implements LevelEntityGetter { @Override public Iterable getAll() { @@ -2055,7 +2038,7 @@ index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5b } public Entity[] getAllCopy() { -@@ -267,7 +272,9 @@ public final class EntityLookup implements LevelEntityGetter { +@@ -269,7 +274,9 @@ public final class EntityLookup implements LevelEntityGetter { if (newVisibility.ordinal() > oldVisibility.ordinal()) { // status upgrade if (!oldVisibility.isAccessible() && newVisibility.isAccessible()) { @@ -2065,7 +2048,7 @@ index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5b EntityLookup.this.worldCallback.onTrackingStart(entity); } -@@ -281,7 +288,9 @@ public final class EntityLookup implements LevelEntityGetter { +@@ -283,7 +290,9 @@ public final class EntityLookup implements LevelEntityGetter { } if (oldVisibility.isAccessible() && !newVisibility.isAccessible()) { @@ -2075,7 +2058,7 @@ index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5b EntityLookup.this.worldCallback.onTrackingEnd(entity); } } -@@ -391,6 +400,8 @@ public final class EntityLookup implements LevelEntityGetter { +@@ -426,6 +435,8 @@ public final class EntityLookup implements LevelEntityGetter { entity.setLevelCallback(new EntityCallback(entity)); @@ -2084,7 +2067,7 @@ index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5b this.entityStatusChange(entity, slices, Visibility.HIDDEN, getEntityStatus(entity), false, !fromDisk, false); return true; -@@ -407,6 +418,19 @@ public final class EntityLookup implements LevelEntityGetter { +@@ -442,6 +453,19 @@ public final class EntityLookup implements LevelEntityGetter { return slices == null || !slices.isPreventingStatusUpdates(); } @@ -2104,15 +2087,26 @@ index ff7198a03ab0da79c98513f4a1507e854484f4c2..26d1e1af418f980b61a57479cbc64b5b private void removeEntity(final Entity entity) { final int sectionX = entity.sectionX; final int sectionY = entity.sectionY; -@@ -427,6 +451,7 @@ public final class EntityLookup implements LevelEntityGetter { - LOGGER.warn("Failed to remove entity " + entity + " from entity slices (" + sectionX + "," + sectionZ + ")"); +@@ -856,12 +880,18 @@ public final class EntityLookup implements LevelEntityGetter { + @Override + public void onMove() { + final Entity entity = this.entity; ++ final io.papermc.paper.threadedregions.RegionizedWorldData regionData = entity.level().getCurrentWorldData(); // Folia - region threading + final Visibility oldVisibility = getEntityStatus(entity); + final ChunkEntitySlices newSlices = EntityLookup.this.moveEntity(this.entity); + if (newSlices == null) { + // no new section, so didn't change sections + return; } - } -+ - entity.sectionX = entity.sectionY = entity.sectionZ = Integer.MIN_VALUE; ++ // Folia start - region threading ++ if (entity instanceof net.minecraft.server.level.ServerPlayer player) { ++ regionData.getNearbyPlayers().tickPlayer(player); ++ } ++ // Folia end - region threading + final Visibility newVisibility = getEntityStatus(entity); - this.entityByLock.writeLock(); -@@ -843,6 +868,9 @@ public final class EntityLookup implements LevelEntityGetter { + EntityLookup.this.entityStatusChange(entity, newSlices, oldVisibility, newVisibility, true, false, false); +@@ -878,6 +908,9 @@ public final class EntityLookup implements LevelEntityGetter { EntityLookup.this.entityStatusChange(entity, null, tickingState, Visibility.HIDDEN, false, false, reason.shouldDestroy()); this.entity.setLevelCallback(NoOpCallback.INSTANCE); @@ -2753,7 +2747,7 @@ index f975cb93716e137d973ff2f9011acdbef58859a2..b84bfc9513a13e365f2bd471b3c77058 if ( !this.radiusAwareGenExecutor.isActive() && diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -index 51304c5cf4b0ac7646693ef97ef4a3847d3342b5..f1c68d9850ece7532a8607db955eaa4fc3a4bf05 100644 +index b66a7d4aab887309579154815a0d4abf9de506b0..08075b8895f816420c2a940bf551dfada3c0cd9e 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java @@ -726,7 +726,7 @@ public final class NewChunkHolder { @@ -2951,10 +2945,10 @@ index bd68139ae635f2ad7ec8e7a21e0056a139c4c62e..48a43341b17247355a531164019d5cc9 } diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 019d3bbd78fb0b06861979d223915fedb6c99442..4588b2d7b97347cbf4202f110fbc5036ccd5b1e0 100644 +index 97a9ce438afc9094dca4a44cb25b37d5f88dcf43..27fcb3a27ad0a853b538ac0bcf7ee996a11b0b0f 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -326,4 +326,17 @@ public class GlobalConfiguration extends ConfigurationPart { +@@ -327,4 +327,17 @@ public class GlobalConfiguration extends ConfigurationPart { public boolean disableChorusPlantUpdates = false; public boolean disableMushroomBlockUpdates = false; } @@ -2973,19 +2967,10 @@ index 019d3bbd78fb0b06861979d223915fedb6c99442..4588b2d7b97347cbf4202f110fbc5036 + // Folia end - threaded regions } diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -index da7c899fbab162ee197a0593f455ebd9c5286d3c..571c18117d7f85eddff31d535c09b46e0e9e4341 100644 +index ec5e23136423e42e4f55e6ea646b8285c1ca14e2..cb56735107028af16efe633f7179ba4c0481b0df 100644 --- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -@@ -145,7 +145,7 @@ public class WorldConfiguration extends ConfigurationPart { - public boolean filterBadTileEntityNbtFromFallingBlocks = true; - public List filteredEntityTagNbtPaths = NbtPathSerializer.fromString(List.of("Pos", "Motion", "SleepingX", "SleepingY", "SleepingZ")); - public boolean disableMobSpawnerSpawnEggTransformation = false; -- public boolean perPlayerMobSpawns = true; -+ //public boolean perPlayerMobSpawns = true; // Folia - region threading - revert per player mob caps - public boolean scanForLegacyEnderDragon = true; - @MergeMap - public Reference2IntMap spawnLimits = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1))); -@@ -459,7 +459,14 @@ public class WorldConfiguration extends ConfigurationPart { +@@ -463,7 +463,14 @@ public class WorldConfiguration extends ConfigurationPart { public Chunks chunks; @@ -3451,10 +3436,10 @@ index 0000000000000000000000000000000000000000..1f48ada99d6d24880f9bda1cd05d41a4 +} diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java new file mode 100644 -index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc0843783fd9 +index 0000000000000000000000000000000000000000..1e3117ccd51be58d988089207a3efdbff02fc374 --- /dev/null +++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java -@@ -0,0 +1,450 @@ +@@ -0,0 +1,455 @@ +package io.papermc.paper.threadedregions; + +import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; @@ -3469,12 +3454,11 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; -+import net.minecraft.network.protocol.game.ClientboundDisconnectPacket; ++import net.minecraft.network.protocol.common.ClientboundDisconnectPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.network.ServerGamePacketListenerImpl; -+import net.minecraft.server.network.ServerLoginPacketListenerImpl; +import net.minecraft.world.level.GameRules; +import org.bukkit.Bukkit; +import org.slf4j.Logger; @@ -3507,7 +3491,7 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 + this.connections.add(conn); + } + -+ private boolean removeConnection(final Connection conn) { ++ public boolean removeConnection(final Connection conn) { + return this.connections.remove(conn); + } + @@ -3788,11 +3772,18 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 + } + } + -+ private boolean hasConnectionMovedToMain(final Connection conn) { ++ public static boolean isNotOwnedByGlobalRegion(final Connection conn) { + final PacketListener packetListener = conn.getPacketListener(); + -+ return (packetListener instanceof ServerGamePacketListenerImpl) || -+ (packetListener instanceof ServerLoginPacketListenerImpl loginListener && loginListener.state.ordinal() >= ServerLoginPacketListenerImpl.State.HANDING_OFF.ordinal()); ++ if (packetListener instanceof ServerGamePacketListenerImpl gamePacketListener) { ++ return !gamePacketListener.waitingForSwitchToConfig; ++ } ++ ++ if (conn.getPacketListener() instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ return configurationPacketListener.switchToMain; ++ } ++ ++ return false; + } + + private void tickConnections() { @@ -3803,10 +3794,9 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 + continue; + } + -+ if (this.hasConnectionMovedToMain(conn)) { -+ if (!conn.isConnected()) { -+ this.removeConnection(conn); -+ } ++ if (isNotOwnedByGlobalRegion(conn)) { ++ // we actually require that the owning regions remove the connection for us, as it is possible ++ // that ownership is transferred back to us + continue; + } + @@ -3823,7 +3813,7 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 + throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection")); + } + -+ LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(conn.getRemoteAddress()) : "", exception); // Paper ++ LOGGER.warn("Failed to handle packet for {}", conn.getLoggableAddress(MinecraftServer.getServer().logIPs()), exception); + MutableComponent ichatmutablecomponent = Component.literal("Internal server error"); + + conn.send(new ClientboundDisconnectPacket(ichatmutablecomponent), PacketSendListener.thenRun(() -> { @@ -3869,7 +3859,7 @@ index 0000000000000000000000000000000000000000..00d79c8095ec689b4a30648665c8fc08 + + world.updateTickData(); + -+ world.chunkTaskScheduler.chunkHolderManager.processTicketUpdates(); // Folia - use area based lock to reduce contention - required now to eventually process ticket updates ++ world.chunkTaskScheduler.chunkHolderManager.processTicketUpdates(); // required to eventually process ticket updates + } + + private void updateRaids(final ServerLevel world) { @@ -4681,10 +4671,10 @@ index 0000000000000000000000000000000000000000..98ddb674b63a4777a98152ea960debf4 +} diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java new file mode 100644 -index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0c5a95cc1 +index 0000000000000000000000000000000000000000..7ca275826609bcf96f103a8c50beaa47c3b4068b --- /dev/null +++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java -@@ -0,0 +1,685 @@ +@@ -0,0 +1,785 @@ +package io.papermc.paper.threadedregions; + +import com.destroystokyo.paper.util.maplist.ReferenceList; @@ -4695,6 +4685,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 +import io.papermc.paper.util.CoordinateUtils; +import io.papermc.paper.util.TickThread; +import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; ++import io.papermc.paper.util.player.NearbyPlayers; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ReferenceMap; +import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; @@ -4707,7 +4698,8 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; -+import net.minecraft.network.protocol.game.ClientboundDisconnectPacket; ++import net.minecraft.network.protocol.common.ClientboundDisconnectPacket; ++import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; @@ -4718,6 +4710,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.level.BlockEventData; +import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.NaturalSpawner; +import net.minecraft.world.level.block.Block; @@ -4738,6 +4731,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; ++import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; @@ -4760,11 +4754,18 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + // entities + for (final ServerPlayer player : from.localPlayers) { + into.localPlayers.add(player); ++ into.nearbyPlayers.addPlayer(player); + } + for (final Entity entity : from.allEntities) { + into.allEntities.add(entity); + entity.updateTicks(fromTickOffset, fromRedstoneTimeOffset); + } ++ for (final Entity entity : from.loadedEntities) { ++ into.loadedEntities.add(entity); ++ } ++ for (final Entity entity : from.toProcessTrackingUnloading) { ++ into.toProcessTrackingUnloading.add(entity); ++ } + for (final Iterator iterator = from.entityTickList.unsafeIterator(); iterator.hasNext();) { + into.entityTickList.add(iterator.next()); + } @@ -4797,6 +4798,9 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + for (final Iterator iterator = from.entityTickingChunks.unsafeIterator(); iterator.hasNext();) { + into.entityTickingChunks.add(iterator.next()); + } ++ for (final Iterator iterator = from.tickingChunks.unsafeIterator(); iterator.hasNext();) { ++ into.tickingChunks.add(iterator.next()); ++ } + // redstone torches + if (from.redstoneUpdateInfos != null && !from.redstoneUpdateInfos.isEmpty()) { + if (into.redstoneUpdateInfos == null) { @@ -4838,8 +4842,9 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + final ChunkPos pos = player.chunkPosition(); + // Note: It is impossible for an entity in the world to _not_ be in an entity chunk, which means + // the chunk holder must _exist_, and so the region section exists. -+ regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)) -+ .localPlayers.add(player); ++ final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)); ++ into.localPlayers.add(player); ++ into.nearbyPlayers.addPlayer(player); + } + for (final Entity entity : from.allEntities) { + final ChunkPos pos = entity.chunkPosition(); @@ -4851,6 +4856,15 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + if (from.entityTickList.contains(entity)) { + into.entityTickList.add(entity); + } ++ // Note: loadedEntities is a subset of allEntities ++ if (from.loadedEntities.contains(entity)) { ++ into.loadedEntities.add(entity); ++ } ++ // Note: toProcessTrackingUnloading is not a subset of allEntities, but for the cases where it is not ++ // do not matter as the tracker removal is handled ++ if (from.toProcessTrackingUnloading.contains(entity)) { ++ into.toProcessTrackingUnloading.add(entity); ++ } + // Note: navigatingMobs is a subset of allEntities + if (entity instanceof Mob mob && from.navigatingMobs.contains(mob)) { + into.navigatingMobs.add(mob); @@ -4922,6 +4936,14 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)) + .entityTickingChunks.add(levelChunk); + } ++ for (final Iterator iterator = from.tickingChunks.unsafeIterator(); iterator.hasNext();) { ++ final LevelChunk levelChunk = iterator.next(); ++ final ChunkPos pos = levelChunk.getPos(); ++ ++ // Impossible for get() to return null, as the chunk is entity ticking - thus the chunk holder is loaded ++ regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)) ++ .tickingChunks.add(levelChunk); ++ } + // redstone torches + if (from.redstoneUpdateInfos != null && !from.redstoneUpdateInfos.isEmpty()) { + for (final net.minecraft.world.level.block.RedstoneTorchBlock.Toggle info : from.redstoneUpdateInfos) { @@ -4980,7 +5002,10 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + + // entities + private final List localPlayers = new ArrayList<>(); ++ private final NearbyPlayers nearbyPlayers; + private final ReferenceList allEntities = new ReferenceList<>(); ++ private final ReferenceList loadedEntities = new ReferenceList<>(); ++ private final ReferenceList toProcessTrackingUnloading = new ReferenceList<>(); + private final IteratorSafeOrderedReferenceSet entityTickList = new IteratorSafeOrderedReferenceSet<>(); + private final IteratorSafeOrderedReferenceSet navigatingMobs = new IteratorSafeOrderedReferenceSet<>(); + @@ -5007,6 +5032,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + + // ticking chunks + private final IteratorSafeOrderedReferenceSet entityTickingChunks = new IteratorSafeOrderedReferenceSet<>(); ++ private final IteratorSafeOrderedReferenceSet tickingChunks = new IteratorSafeOrderedReferenceSet<>(); + private final IteratorSafeOrderedReferenceSet chunks = new IteratorSafeOrderedReferenceSet<>(); + + // Paper/CB api hook misc @@ -5043,6 +5069,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + @VisibleForDebug + public NaturalSpawner.SpawnState lastSpawnState; + public boolean shouldSignal = true; ++ public final Map explosionDensityCache = new HashMap<>(64, 0.25f); + + // not transient + public java.util.ArrayDeque redstoneUpdateInfos; @@ -5104,6 +5131,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + this.blockLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world.getProfilerSupplier(), world, true); + this.fluidLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world.getProfilerSupplier(), world, false); + this.neighborUpdater = new CollectingNeighborUpdater(world, world.neighbourUpdateMax); ++ this.nearbyPlayers = new NearbyPlayers(world); + + // tasks may be drained before the region ticks, so we must set up the tick data early just in case + this.updateTickData(); @@ -5119,11 +5147,34 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + return this.tickData; + } + ++ private long lagCompensationTick; ++ ++ public long getLagCompensationTick() { ++ return this.lagCompensationTick; ++ } ++ + public void updateTickData() { + this.tickData = this.world.tickData; + this.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + this.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + this.skipHopperEvents = this.world.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper ++ // always subtract from server init so that the tick starts at zero, allowing us to cast to int without much worry ++ this.lagCompensationTick = (System.nanoTime() - MinecraftServer.SERVER_INIT) / TickRegionScheduler.TIME_BETWEEN_TICKS; ++ } ++ ++ public NearbyPlayers getNearbyPlayers() { ++ return this.nearbyPlayers; ++ } ++ ++ private static void cleanUpConnection(final Connection conn) { ++ // note: ALL connections HERE have a player ++ final ServerPlayer player = conn.getPlayer(); ++ // now that the connection is removed, we can allow this region to die ++ player.serverLevel().chunkSource.removeTicketAtLevel( ++ ServerGamePacketListenerImpl.DISCONNECT_TICKET, player.connection.disconnectPos, ++ ChunkHolderManager.MAX_TICKET_LEVEL, ++ player.connection.disconnectTicketId ++ ); + } + + // connections @@ -5133,15 +5184,10 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + for (final Connection conn : connections) { + if (!conn.isConnected()) { + conn.handleDisconnection(); ++ // global tick thread will not remove connections not owned by it, so we need to ++ RegionizedServer.getInstance().removeConnection(conn); + this.connections.remove(conn); -+ // note: ALL connections HERE have a player -+ final ServerPlayer player = conn.getPlayer(); -+ // now that the connection is removed, we can allow this region to die -+ player.serverLevel().chunkSource.removeTicketAtLevel( -+ ServerGamePacketListenerImpl.DISCONNECT_TICKET, player.connection.disconnectPos, -+ ChunkHolderManager.MAX_TICKET_LEVEL, -+ player.connection.disconnectTicketId -+ ); ++ cleanUpConnection(conn); + continue; + } + if (!this.connections.contains(conn)) { @@ -5156,7 +5202,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection")); + } + -+ LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(conn.getRemoteAddress()) : "", exception); // Paper ++ LOGGER.warn("Failed to handle packet for {}", conn.getLoggableAddress(MinecraftServer.getServer().logIPs()), exception); + MutableComponent ichatmutablecomponent = Component.literal("Internal server error"); + + conn.send(new ClientboundDisconnectPacket(ichatmutablecomponent), PacketSendListener.thenRun(() -> { @@ -5189,6 +5235,34 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + return this.localPlayers; + } + ++ public void addLoadedEntity(final Entity entity) { ++ if (this.loadedEntities.add(entity)) { ++ this.toProcessTrackingUnloading.remove(entity); ++ } ++ } ++ ++ public boolean hasLoadedEntity(final Entity entity) { ++ return this.loadedEntities.contains(entity); ++ } ++ ++ public void removeLoadedEntity(final Entity entity) { ++ if (this.loadedEntities.remove(entity)) { ++ this.toProcessTrackingUnloading.add(entity); ++ } ++ } ++ ++ public Iterable getLoadedEntities() { ++ return this.loadedEntities; ++ } ++ ++ public Entity[] takeTrackingUnloads() { ++ final Entity[] ret = Arrays.copyOf(this.toProcessTrackingUnloading.getRawData(), this.toProcessTrackingUnloading.size(), Entity[].class); ++ ++ this.toProcessTrackingUnloading.clear(); ++ ++ return ret; ++ } ++ + public void addEntityTickingEntity(final Entity entity) { + if (!TickThread.isTickThreadFor(entity)) { + throw new IllegalArgumentException("Entity " + entity + " is not under this region's control"); @@ -5227,6 +5301,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + if (this.allEntities.add(entity)) { + if (entity instanceof ServerPlayer player) { + this.localPlayers.add(player); ++ this.nearbyPlayers.addPlayer(player); + } + TickRegions.RegionStats.updateCurrentRegion(); + } @@ -5243,6 +5318,7 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + if (this.allEntities.remove(entity)) { + if (entity instanceof ServerPlayer player) { + this.localPlayers.remove(player); ++ this.nearbyPlayers.removePlayer(player); + } + TickRegions.RegionStats.updateCurrentRegion(); + } @@ -5348,6 +5424,20 @@ index 0000000000000000000000000000000000000000..41db6c61de36ebb1c214423dca0ba6a0 + return this.entityTickingChunks; + } + ++ public void addTickingChunk(final LevelChunk levelChunk) { ++ this.tickingChunks.add(levelChunk); ++ TickRegions.RegionStats.updateCurrentRegion(); ++ } ++ ++ public void removeTickingChunk(final LevelChunk levelChunk) { ++ this.tickingChunks.remove(levelChunk); ++ TickRegions.RegionStats.updateCurrentRegion(); ++ } ++ ++ public IteratorSafeOrderedReferenceSet getTickingChunks() { ++ return this.tickingChunks; ++ } ++ + public void addChunk(final LevelChunk levelChunk) { + this.chunks.add(levelChunk); + TickRegions.RegionStats.updateCurrentRegion(); @@ -9185,22 +9275,18 @@ index e08f4e39db4ee3fed62e37364d17dcc5c5683504..7e92e14cdb9f3d895550991b2ea154a6 } } diff --git a/src/main/java/io/papermc/paper/util/CollisionUtil.java b/src/main/java/io/papermc/paper/util/CollisionUtil.java -index a87f6380b2c387fb0cdd40d5087b5c93492e3c88..77d369ca6be814d1f5a19ec37b44800529e6cda3 100644 +index bfb1de19f53d5d7c7b65e25a606fabfa416706b3..61e51d68df3bc5be3622c32025af9cb418b4ca75 100644 --- a/src/main/java/io/papermc/paper/util/CollisionUtil.java +++ b/src/main/java/io/papermc/paper/util/CollisionUtil.java -@@ -480,7 +480,12 @@ public final class CollisionUtil { - if (chunkProvider == null) { - chunk = (ChunkAccess)getter.getChunkForCollisions(currChunkX, currChunkZ); - } else { -+ // Folia start - ignore chunk if we do not own the region -+ if (!io.papermc.paper.util.TickThread.isTickThreadFor(chunkProvider.chunkMap.level, currChunkX, currChunkZ)) { -+ chunk = null; -+ } else { // Folia end - ignore chunk if we do not own the region - chunk = loadChunks ? chunkProvider.getChunk(currChunkX, currChunkZ, true) : chunkProvider.getChunkAtIfLoadedImmediately(currChunkX, currChunkZ); -+ } // Folia - ignore chunk if we do not own the region - } +@@ -1648,7 +1648,7 @@ public final class CollisionUtil { + + for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { + for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { +- final ChunkAccess chunk = loadChunks ? chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, true) : chunkSource.getChunkAtIfLoadedImmediately(currChunkX, currChunkZ); ++ final ChunkAccess chunk = !io.papermc.paper.util.TickThread.isTickThreadFor(chunkSource.chunkMap.level, currChunkX, currChunkZ) ? null : (loadChunks ? chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, true) : chunkSource.getChunkAtIfLoadedImmediately(currChunkX, currChunkZ)); // Folia - ignore chunk if we do not own the region if (chunk == null) { + if ((collisionFlags & COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS) != 0) { diff --git a/src/main/java/io/papermc/paper/util/CoordinateUtils.java b/src/main/java/io/papermc/paper/util/CoordinateUtils.java index 413e4b6da027876dbbe8eb78f2568a440f431547..3a7dbcb9964723b8ed5e6b0a1ee4267923c746e4 100644 --- a/src/main/java/io/papermc/paper/util/CoordinateUtils.java @@ -9246,10 +9332,10 @@ index 413e4b6da027876dbbe8eb78f2568a440f431547..3a7dbcb9964723b8ed5e6b0a1ee42679 throw new RuntimeException(); } diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index c69088a2ec374b2d236fec61e267f42afa2967b1..cadb91c7f5ef80aac8513f246fdf481947fa0a17 100644 +index d02546b18cb689724887b4e85e8d32a18828a4ad..2d6fc460c850c6d515794d2fa29324a448a985d1 100644 --- a/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -338,6 +338,7 @@ public final class MCUtil { +@@ -336,6 +336,7 @@ public final class MCUtil { */ public static void ensureMain(String reason, Runnable run) { if (!isMainThread()) { @@ -9257,7 +9343,7 @@ index c69088a2ec374b2d236fec61e267f42afa2967b1..cadb91c7f5ef80aac8513f246fdf4819 if (reason != null) { MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); } -@@ -478,6 +479,30 @@ public final class MCUtil { +@@ -476,6 +477,30 @@ public final class MCUtil { return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); } @@ -9289,7 +9375,7 @@ index c69088a2ec374b2d236fec61e267f42afa2967b1..cadb91c7f5ef80aac8513f246fdf4819 * Converts an NMS entity's current location to a Bukkit Location * @param entity diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java -index f9063e2282f89e97a378f06822cde0a64ab03f9a..cb453dd110fc37fae75257a4576512126207763e 100644 +index f9063e2282f89e97a378f06822cde0a64ab03f9a..c6b3c747d4c9792c3b690af4d45b13d2b05039ee 100644 --- a/src/main/java/io/papermc/paper/util/TickThread.java +++ b/src/main/java/io/papermc/paper/util/TickThread.java @@ -1,5 +1,11 @@ @@ -9304,7 +9390,7 @@ index f9063e2282f89e97a378f06822cde0a64ab03f9a..cb453dd110fc37fae75257a457651212 import net.minecraft.core.BlockPos; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -@@ -114,46 +120,125 @@ public class TickThread extends Thread { +@@ -114,46 +120,137 @@ public class TickThread extends Thread { } public static boolean isShutdownThread() { @@ -9412,7 +9498,19 @@ index f9063e2282f89e97a378f06822cde0a64ab03f9a..cb453dd110fc37fae75257a457651212 + if (region == null) { + if (RegionizedServer.isGlobalTickThread()) { + if (entity instanceof ServerPlayer serverPlayer) { -+ return serverPlayer.connection == null; ++ final ServerGamePacketListenerImpl possibleBad = serverPlayer.connection; ++ if (possibleBad == null) { ++ return true; ++ } ++ ++ final net.minecraft.network.PacketListener packetListener = possibleBad.connection.getPacketListener(); ++ if (packetListener instanceof ServerGamePacketListenerImpl gamePacketListener) { ++ return gamePacketListener.waitingForSwitchToConfig; ++ } ++ if (packetListener instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ return !configurationPacketListener.switchToMain; ++ } ++ return true; + } else { + return false; + } @@ -9720,39 +9818,8 @@ index 0000000000000000000000000000000000000000..cf9b66afc1762dbe2c625f09f9e804ca + } + } +} -diff --git a/src/main/java/net/minecraft/advancements/CriterionProgress.java b/src/main/java/net/minecraft/advancements/CriterionProgress.java -index f40d6eaa6ebbd775cd3feb41546423fe4cbf2b22..e43c95e3be6cb41eab0a1cecbf154350e70b7b79 100644 ---- a/src/main/java/net/minecraft/advancements/CriterionProgress.java -+++ b/src/main/java/net/minecraft/advancements/CriterionProgress.java -@@ -12,7 +12,7 @@ import javax.annotation.Nullable; - import net.minecraft.network.FriendlyByteBuf; - - public class CriterionProgress { -- private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT); -+ private static final ThreadLocal DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT)); // Folia - region threading - SDF is not thread-safe - @Nullable - private Date obtained; - -@@ -43,7 +43,7 @@ public class CriterionProgress { - } - - public JsonElement serializeToJson() { -- return (JsonElement)(this.obtained != null ? new JsonPrimitive(DATE_FORMAT.format(this.obtained)) : JsonNull.INSTANCE); -+ return (JsonElement)(this.obtained != null ? new JsonPrimitive(DATE_FORMAT.get().format(this.obtained)) : JsonNull.INSTANCE); // Folia - region threading - SDF is not thread-safe - } - - public static CriterionProgress fromNetwork(FriendlyByteBuf buf) { -@@ -56,7 +56,7 @@ public class CriterionProgress { - CriterionProgress criterionProgress = new CriterionProgress(); - - try { -- criterionProgress.obtained = DATE_FORMAT.parse(datetime); -+ criterionProgress.obtained = DATE_FORMAT.get().parse(datetime); // Folia - region threading - SDF is not thread-safe - return criterionProgress; - } catch (ParseException var3) { - throw new JsonSyntaxException("Invalid datetime: " + datetime, var3); diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index 0de2eae2d448ac9e269a4edf48406d5ea8af8059..f026dce09c49cbea3b3c207c12d0e4e718063c83 100644 +index 56ae02aab93b9a698e9d2f07a0448aa4767169d9..4e196b4e7bc8ac6da8d3e61e68bdf461c7ea821f 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -69,7 +69,7 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy @@ -9765,10 +9832,10 @@ index 0de2eae2d448ac9e269a4edf48406d5ea8af8059..f026dce09c49cbea3b3c207c12d0e4e7 } diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df07a0f8a1 100644 +index 3eec879bf3975636739b2491cc05b8177032d16d..4f6bd2d88219ac82c4d08c35231e5d3314f87110 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -144,13 +144,13 @@ public class Commands { +@@ -146,13 +146,13 @@ public class Commands { AdvancementCommands.register(this.dispatcher); AttributeCommand.register(this.dispatcher, commandRegistryAccess); ExecuteCommand.register(this.dispatcher, commandRegistryAccess); @@ -9787,7 +9854,7 @@ index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df DefaultGameModeCommands.register(this.dispatcher); DifficultyCommand.register(this.dispatcher); EffectCommands.register(this.dispatcher, commandRegistryAccess); -@@ -160,46 +160,46 @@ public class Commands { +@@ -162,47 +162,47 @@ public class Commands { FillCommand.register(this.dispatcher, commandRegistryAccess); FillBiomeCommand.register(this.dispatcher, commandRegistryAccess); ForceLoadCommand.register(this.dispatcher); @@ -9809,7 +9876,9 @@ index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df ParticleCommand.register(this.dispatcher, commandRegistryAccess); PlaceCommand.register(this.dispatcher); PlaySoundCommand.register(this.dispatcher); +- RandomCommand.register(this.dispatcher); - ReloadCommand.register(this.dispatcher); ++ //RandomCommand.register(this.dispatcher); // Folia - region threading + //ReloadCommand.register(this.dispatcher); // Folia - region threading RecipeCommand.register(this.dispatcher); - ReturnCommand.register(this.dispatcher); @@ -9849,7 +9918,7 @@ index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df if (JvmProfiler.INSTANCE.isAvailable()) { JfrCommand.register(this.dispatcher); } -@@ -217,8 +217,8 @@ public class Commands { +@@ -223,8 +223,8 @@ public class Commands { OpCommand.register(this.dispatcher); PardonCommand.register(this.dispatcher); PardonIpCommand.register(this.dispatcher); @@ -9860,7 +9929,7 @@ index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df SaveOffCommand.register(this.dispatcher); SaveOnCommand.register(this.dispatcher); SetPlayerIdleTimeoutCommand.register(this.dispatcher); -@@ -448,9 +448,12 @@ public class Commands { +@@ -454,9 +454,12 @@ public class Commands { } // Paper start - Async command map building new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper @@ -9877,10 +9946,10 @@ index 80c2c8d565f03ae0ea24fbdecdbe2bc5b9aa4b82..681cd79ce24fe5d952e987d46e2fd8df private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { diff --git a/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java -index 309ad5a1da6b3a297d5526cd9247359ac5f49406..5a85fcbcd2966af95683106d4f459653983a28e6 100644 +index 155bd3d6d9c7d3cac7fd04de8210301251d1e17a..446f590dcf8f1d30b365e71515683c9a592a608b 100644 --- a/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java -@@ -33,7 +33,7 @@ public abstract class AbstractProjectileDispenseBehavior extends DefaultDispense +@@ -32,7 +32,7 @@ public abstract class AbstractProjectileDispenseBehavior extends DefaultDispense CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) enumdirection.getStepX(), (double) ((float) enumdirection.getStepY() + 0.1F), (double) enumdirection.getStepZ())); @@ -9890,10 +9959,10 @@ index 309ad5a1da6b3a297d5526cd9247359ac5f49406..5a85fcbcd2966af95683106d4f459653 } diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -index 573244877f096c4ff4c68f7fcfd21f7423da1104..fd2cc58e6cec72b0ec77af79c12e155efba568e3 100644 +index 80dbeb0a988c749feaaba26ce5ad93c181d88a5d..e92d8c8f6b208642e87cdb4080d3b38f95d84503 100644 --- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -@@ -60,7 +60,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { +@@ -62,7 +62,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3)); @@ -9903,7 +9972,7 @@ index 573244877f096c4ff4c68f7fcfd21f7423da1104..fd2cc58e6cec72b0ec77af79c12e155e } diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -index 1e6ba6d9cceda1d4867b183c3dbc03d317ed287f..de8cf0f0d34708b960f1c81cb10d813a797df02b 100644 +index 379890ae05b2fb4bd81b2fa907413d3736ba1169..4ea33c913b005d81a600215ac35a644ee1396cb3 100644 --- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java @@ -74,7 +74,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { @@ -9916,7 +9985,7 @@ index 1e6ba6d9cceda1d4867b183c3dbc03d317ed287f..de8cf0f0d34708b960f1c81cb10d813a } diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6064029c4 100644 +index a0c7c6208314d981e8577ad69ef1c5193290a085..f0c2ee38e9101a6c593f6deb6b8101b72ad4a067 100644 --- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java @@ -222,7 +222,7 @@ public interface DispenseItemBehavior { @@ -9991,7 +10060,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -706,7 +706,7 @@ public interface DispenseItemBehavior { +@@ -707,7 +707,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); @@ -10000,8 +10069,8 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -753,7 +753,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items +@@ -754,7 +754,7 @@ public interface DispenseItemBehavior { + CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); - if (!DispenserBlock.eventFired) { @@ -10009,7 +10078,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -814,7 +814,7 @@ public interface DispenseItemBehavior { +@@ -815,7 +815,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); @@ -10018,7 +10087,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -832,7 +832,8 @@ public interface DispenseItemBehavior { +@@ -833,7 +833,8 @@ public interface DispenseItemBehavior { } } @@ -10028,7 +10097,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 // CraftBukkit end if (!BoneMealItem.growCrop(stack, worldserver, blockposition) && !BoneMealItem.growWaterPlant(stack, worldserver, blockposition, (Direction) null)) { -@@ -841,13 +842,13 @@ public interface DispenseItemBehavior { +@@ -842,13 +843,13 @@ public interface DispenseItemBehavior { worldserver.levelEvent(1505, blockposition, 0); } // CraftBukkit start @@ -10048,7 +10117,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 StructureGrowEvent structureEvent = null; if (treeType != null) { structureEvent = new StructureGrowEvent(location, treeType, false, null, blocks); -@@ -882,7 +883,7 @@ public interface DispenseItemBehavior { +@@ -884,7 +885,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D)); @@ -10057,7 +10126,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -939,7 +940,7 @@ public interface DispenseItemBehavior { +@@ -941,7 +942,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); @@ -10066,7 +10135,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -988,7 +989,7 @@ public interface DispenseItemBehavior { +@@ -990,7 +991,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); @@ -10075,7 +10144,7 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 worldserver.getCraftServer().getPluginManager().callEvent(event); } -@@ -1061,7 +1062,7 @@ public interface DispenseItemBehavior { +@@ -1063,7 +1064,7 @@ public interface DispenseItemBehavior { CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - only single item in event BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); @@ -10085,11 +10154,11 @@ index 70aade6a8d36f8376cc567800258ea6fabb0607f..ab5b07a50f1742acb175a5fc0446e9c6 } diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index 9b0049dfeaec9b688bf276f2ac2b18943b5696b2..a9cd926d5b7177e7d9bf35ed1614e2c917b16931 100644 +index e17090003988ad2c890d48666c2234b14d511345..5bce4ad0d3025def91649592ec8610b975f8ac8a 100644 --- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java @@ -40,7 +40,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items + CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); - if (!DispenserBlock.eventFired) { @@ -10098,7 +10167,7 @@ index 9b0049dfeaec9b688bf276f2ac2b18943b5696b2..a9cd926d5b7177e7d9bf35ed1614e2c9 } diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -index 0159ed9cbc644c39fa79e62327f13375193fdc98..a930c8eb64d6c7044646d6b0156e202ea334a1f9 100644 +index 6f2adf2334e35e8a617a4ced0c1af2abf32bbd8d..de323c881b6d54061f7fef2b56658bebc2d71604 100644 --- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java @@ -37,7 +37,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { @@ -10106,33 +10175,33 @@ index 0159ed9cbc644c39fa79e62327f13375193fdc98..a930c8eb64d6c7044646d6b0156e202e BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); - if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get()) { // Folia - region threading - pointer.getLevel().getCraftServer().getPluginManager().callEvent(event); ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + pointer.level().getCraftServer().getPluginManager().callEvent(event); } diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2cf3d7b19d 100644 +index c0ea20dcee8bb293df96bc6ee019e50ad6b383fd..b84e9d5ae5efe1a8257a5f1f78a0ab66113a698e 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java -@@ -73,7 +73,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -84,7 +84,7 @@ public class Connection extends SimpleChannelInboundHandler> { return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper }); private final PacketFlow receiving; -- private final Queue queue = Queues.newConcurrentLinkedQueue(); -+ private final Queue queue = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); +- private final Queue pendingActions = Queues.newConcurrentLinkedQueue(); ++ private final Queue pendingActions = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); // Folia - region threading - connection fixes public Channel channel; public SocketAddress address; // Spigot Start -@@ -81,7 +81,7 @@ public class Connection extends SimpleChannelInboundHandler> { - public com.mojang.authlib.properties.Property[] spoofedProfile; - public boolean preparing = true; - // Spigot End -- private PacketListener packetListener; -+ private volatile PacketListener packetListener; // Folia - region threading +@@ -99,7 +99,7 @@ public class Connection extends SimpleChannelInboundHandler> { + @Nullable private Component disconnectedReason; private boolean encrypted; - private boolean disconnectionHandled; -@@ -179,6 +179,32 @@ public class Connection extends SimpleChannelInboundHandler> { +- private boolean disconnectionHandled; ++ private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage + private int receivedPackets; + private int sentPackets; + private float averageReceivedPackets; +@@ -153,6 +153,32 @@ public class Connection extends SimpleChannelInboundHandler> { this.receiving = side; } @@ -10158,14 +10227,14 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c + } + + public final boolean isPlayerConnected() { -+ return this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl; ++ return this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl; + } + // Folia end - region threading + public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception { super.channelActive(channelhandlercontext); this.channel = channelhandlercontext.channel(); -@@ -196,7 +222,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -163,7 +189,7 @@ public class Connection extends SimpleChannelInboundHandler> { if (this.delayedDisconnect != null) { this.disconnect(this.delayedDisconnect); } @@ -10173,65 +10242,91 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c + this.becomeActive = true; // Folia - region threading } - public void setProtocol(ConnectionProtocol state) { -@@ -385,13 +411,6 @@ public class Connection extends SimpleChannelInboundHandler> { - return; // Do nothing + public static void setInitialProtocolAttributes(Channel channel) { +@@ -386,7 +412,7 @@ public class Connection extends SimpleChannelInboundHandler> { } - packet.onPacketDispatch(getPlayer()); -- if (connected && (InnerUtil.canSendImmediate(this, packet) || ( -- io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && -- (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) -- ))) { -- this.sendPacket(packet, callbacks, null); // Paper -- return; -- } - // write the packets to the queue, then flush - antixray hooks there already - java.util.List extraPackets = InnerUtil.buildExtraPackets(packet); - boolean hasExtraPackets = extraPackets != null && !extraPackets.isEmpty(); -@@ -513,66 +532,58 @@ public class Connection extends SimpleChannelInboundHandler> { - // Paper start - rewrite this to be safer if ran off main thread - private boolean flushQueue() { // void -> boolean -- if (!isConnected()) { -+ if (!this.isConnected()) { - return true; + packet.onPacketDispatch(this.getPlayer()); +- if (connected && (InnerUtil.canSendImmediate(this, packet) ++ if (false && connected && (InnerUtil.canSendImmediate(this, packet) // Folia - region threading - connection fixes + || (io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.pendingActions.isEmpty() + && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty())))) { + this.sendPacket(packet, callbacks, flush); +@@ -415,11 +441,12 @@ public class Connection extends SimpleChannelInboundHandler> { + } + + public void runOnceConnected(Consumer task) { +- if (this.isConnected()) { ++ if (false && this.isConnected()) { // Folia - region threading - connection fixes + this.flushQueue(); + task.accept(this); + } else { + this.pendingActions.add(new WrappedConsumer(task)); // Paper - Optimize network ++ this.flushQueue(); // Folia - region threading - connection fixes } + + } +@@ -478,10 +505,11 @@ public class Connection extends SimpleChannelInboundHandler> { + } + + public void flushChannel() { +- if (this.isConnected()) { ++ if (false && this.isConnected()) { // Folia - region threading - connection fixes + this.flush(); + } else { + this.pendingActions.add(new WrappedConsumer(Connection::flush)); // Paper - Optimize network ++ this.flushQueue(); // Folia - region threading - connection fixes + } + + } +@@ -516,53 +544,61 @@ public class Connection extends SimpleChannelInboundHandler> { + + // Paper start - Optimize network: Rewrite this to be safer if ran off main thread + private boolean flushQueue() { +- if (!this.isConnected()) { +- return true; +- } - if (io.papermc.paper.util.MCUtil.isMainThread()) { -- return processQueue(); -- } else if (isPending) { +- return this.processQueue(); +- } else if (this.isPending) { - // Should only happen during login/status stages -- synchronized (this.queue) { +- synchronized (this.pendingActions) { - return this.processQueue(); - } - } - return false; -+ return this.processQueue(); -+ } -+ ++ return this.processQueue(); // Folia - region threading - connection fixes + } + ++ // Folia start - region threading - connection fixes + // allow only one thread to be flushing the queue at once to ensure packets are written in the order they are sent + // into the queue + private final java.util.concurrent.atomic.AtomicBoolean flushingQueue = new java.util.concurrent.atomic.AtomicBoolean(); + ++ private static boolean canWrite(WrappedConsumer queued) { ++ return queued != null && (!(queued instanceof PacketSendAction packet) || packet.packet.isReady()); ++ } ++ + private boolean canWritePackets() { -+ PacketHolder holder = this.queue.peek(); -+ return holder != null && holder.packet.isReady(); - } ++ return canWrite(this.pendingActions.peek()); ++ } ++ // Folia end - region threading - connection fixes + private boolean processQueue() { -- try { // Paper - add pending task queue -- if (this.queue.isEmpty()) return true; -- // Paper start - make only one flush call per sendPacketQueue() call - final boolean needsFlush = this.canFlush; -- boolean hasWrotePacket = false; -- // Paper end - make only one flush call per sendPacketQueue() call +- if (this.pendingActions.isEmpty()) { ++ // Folia start - region threading - connection fixes ++ if (!this.isConnected()) { + return true; + } + - // If we are on main, we are safe here in that nothing else should be processing queue off main anymore - // But if we are not on main due to login/status, the parent is synchronized on packetQueue -- java.util.Iterator iterator = this.queue.iterator(); +- final java.util.Iterator iterator = this.pendingActions.iterator(); - while (iterator.hasNext()) { -- PacketHolder queued = iterator.next(); // poll -> peek +- final WrappedConsumer queued = iterator.next(); // poll -> peek - - // Fix NPE (Spigot bug caused by handleDisconnection()) -- if (false && queued == null) { // Paper - diff on change, this logic is redundant: iterator guarantees ret of an element - on change, hook the flush logic here +- if (queued == null) { - return true; - } + while (this.canWritePackets()) { @@ -10242,59 +10337,45 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c + return false; + } -- // Paper start - checking isConsumed flag and skipping packet sending - if (queued.isConsumed()) { - continue; - } -- // Paper end - checking isConsumed flag and skipping packet sending -+ boolean justFlushed = true; -+ -+ PacketHolder holder; ++ ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue queue = ++ (ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue)this.pendingActions; ++ WrappedConsumer holder; + for (;;) { + // synchronise so that queue clears appear atomic -+ synchronized (this.queue) { -+ holder = ((ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue)this.queue).pollIf((PacketHolder h) -> { -+ return h.packet.isReady(); -+ }); ++ synchronized (queue) { ++ holder = queue.pollIf(Connection::canWrite); + } + if (holder == null) { + break; + } -+ justFlushed = (!this.canWritePackets() && (needsFlush || this.canFlush)); -+ this.sendPacket(holder.packet, holder.listener, justFlushed ? Boolean.TRUE : Boolean.FALSE); // Paper - make only one flush call per sendPacketQueue() call -+ } -- Packet packet = queued.packet; -- if (!packet.isReady()) { -- // Paper start - make only one flush call per sendPacketQueue() call -- if (hasWrotePacket && (needsFlush || this.canFlush)) { -+ if (!justFlushed) { - this.flush(); +- if (queued instanceof PacketSendAction packetSendAction) { +- final Packet packet = packetSendAction.packet; +- if (!packet.isReady()) { +- return false; ++ holder.accept(this); } -- // Paper end - make only one flush call per sendPacketQueue() call -- return false; -- } else { -- iterator.remove(); -- if (queued.tryMarkConsumed()) { // Paper - try to mark isConsumed flag for de-duplicating packet -- this.sendPacket(packet, queued.listener, (!iterator.hasNext() && (needsFlush || this.canFlush)) ? Boolean.TRUE : Boolean.FALSE); // Paper - make only one flush call per sendPacketQueue() call -- hasWrotePacket = true; // Paper - make only one flush call per sendPacketQueue() call +- } + +- iterator.remove(); +- if (queued.tryMarkConsumed()) { +- queued.accept(this); + } finally { + if (!set) { + this.flushingQueue.set(false); - } ++ } } } ++ return true; -- } finally { // Paper start - add pending task queue -- Runnable r; -- while ((r = this.pendingTasks.poll()) != null) { -- this.channel.eventLoop().execute(r); -- } -- } // Paper end - add pending task queue ++ // Folia end - region threading - connection fixes } - // Paper end + // Paper end - Optimize network -@@ -581,21 +592,41 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -571,21 +607,41 @@ public class Connection extends SimpleChannelInboundHandler> { private static int currTick; // Paper public void tick() { this.flushQueue(); @@ -10312,8 +10393,8 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c + loginPacketListener.disconnect(disconnectReq.disconnectReason); + // this doesn't fail, so abort any further attempts + return; -+ } else if (packetlistener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { -+ gamePacketListener.disconnect(disconnectReq.disconnectReason, disconnectReq.cause); ++ } else if (packetlistener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { ++ commonPacketListener.disconnect(disconnectReq.disconnectReason, disconnectReq.cause); + // may be cancelled by a plugin, if not cancelled then any further calls do nothing + continue; + } else { @@ -10338,38 +10419,22 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c // Paper start - limit the number of joins which can be processed each tick - if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) -- || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT +- || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING - || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { + if (true) { // Folia - region threading // Paper start - detailed watchdog information net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); try { // Paper end - detailed watchdog information -@@ -635,13 +666,21 @@ public class Connection extends SimpleChannelInboundHandler> { - // Paper start - public void clearPacketQueue() { - net.minecraft.server.level.ServerPlayer player = getPlayer(); -- queue.forEach(queuedPacket -> { -+ java.util.List queuedPackets = new java.util.ArrayList<>(); -+ // synchronise so that flushQueue does not poll values while the queue is being cleared -+ synchronized (this.queue) { -+ Connection.PacketHolder packetHolder; -+ while ((packetHolder = this.queue.poll()) != null) { -+ queuedPackets.add(packetHolder); -+ } -+ } -+ -+ for (Connection.PacketHolder queuedPacket : queuedPackets) { - Packet packet = queuedPacket.packet; - if (packet.hasFinishListener()) { - packet.onPacketDispatchFinish(player, null); - } -- }); -- queue.clear(); -+ } - } - // Paper end - public void disconnect(Component disconnectReason) { -@@ -657,6 +696,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -597,7 +653,7 @@ public class Connection extends SimpleChannelInboundHandler> { + // Paper end + } + +- if (!this.isConnected() && !this.disconnectionHandled) { ++ if (!this.isConnected()) {// Folia - region threading - it's fine to call if it is already handled, as it no longer logs + this.handleDisconnection(); + } + +@@ -643,6 +699,7 @@ public class Connection extends SimpleChannelInboundHandler> { this.channel.close(); // We can't wait as this may be called from an event loop. this.disconnectedReason = disconnectReason; } @@ -10377,51 +10442,78 @@ index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..f6ccb6eab566b44c3460376d46df1f2c } -@@ -825,13 +865,27 @@ public class Connection extends SimpleChannelInboundHandler> { - final net.minecraft.server.network.ServerGamePacketListenerImpl playerConnection = (net.minecraft.server.network.ServerGamePacketListenerImpl) packetListener; - new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(playerConnection.player.getUUID(), - playerConnection.player.getScoreboardName(), ((java.net.InetSocketAddress)address).getAddress(), false).callEvent(); -+ // Note: It can be in the connection set if it is in ready to accept if handleAcceptedLogin fails -+ // Folia start - region threading +@@ -822,10 +879,10 @@ public class Connection extends SimpleChannelInboundHandler> { + + public void handleDisconnection() { + if (this.channel != null && !this.channel.isOpen()) { +- if (this.disconnectionHandled) { ++ if (this.disconnectionHandled.getAndSet(true)) { // Folia - region threading - may be called concurrently during configuration stage + // Connection.LOGGER.warn("handleDisconnection() called twice"); // Paper - Don't log useless message + } else { +- this.disconnectionHandled = true; ++ // Folia - region threading - may be called concurrently during configuration stage - set above + PacketListener packetlistener = this.getPacketListener(); + PacketListener packetlistener1 = packetlistener != null ? packetlistener : this.disconnectListener; + +@@ -856,6 +913,21 @@ public class Connection extends SimpleChannelInboundHandler> { + ((java.net.InetSocketAddress)address).getAddress(), false).callEvent(); + } + } ++ // Folia start - region threading ++ if (packetlistener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { + net.minecraft.server.MinecraftServer.getServer().getPlayerList().removeConnection( -+ playerConnection.player.getScoreboardName(), -+ playerConnection.player.getUUID(), this ++ commonPacketListener.getOwner().getName(), ++ commonPacketListener.getOwner().getId(), this + ); -+ // Folia end - region threading - } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl) { - /* Player is login stage */ - final net.minecraft.server.network.ServerLoginPacketListenerImpl loginListener = (net.minecraft.server.network.ServerLoginPacketListenerImpl) packetListener; -- switch (loginListener.state) { -- case READY_TO_ACCEPT: -- case DELAY_ACCEPT: -- case ACCEPTED: -+ // Folia start - region threading -+ if (loginListener.state.ordinal() >= net.minecraft.server.network.ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT.ordinal()) { -+ // Note: It can be in the connection set if it is in ready to accept if handleAcceptedLogin fails ++ } else if (packetlistener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { ++ if (loginPacketListener.state.ordinal() >= net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING.ordinal()) { + net.minecraft.server.MinecraftServer.getServer().getPlayerList().removeConnection( -+ loginListener.gameProfile.getName(), -+ net.minecraft.core.UUIDUtil.getOrCreatePlayerUUID(loginListener.gameProfile), -+ this ++ loginPacketListener.authenticatedProfile.getName(), ++ loginPacketListener.authenticatedProfile.getId(), this + ); + } -+ // Folia end - region threading -+ if (loginListener.state.ordinal() >= net.minecraft.server.network.ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT.ordinal()) { // Folia - region threading - rewrite login process - final com.mojang.authlib.GameProfile profile = loginListener.gameProfile; /* Should be non-null at this stage */ - new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), profile.getName(), - ((java.net.InetSocketAddress)address).getAddress(), false).callEvent(); ++ } ++ // Folia end - region threading + // Paper end + + } +@@ -877,15 +949,25 @@ public class Connection extends SimpleChannelInboundHandler> { + // Paper start - Optimize network + public void clearPacketQueue() { + final net.minecraft.server.level.ServerPlayer player = getPlayer(); +- for (final Consumer queuedAction : this.pendingActions) { +- if (queuedAction instanceof PacketSendAction packetSendAction) { +- final Packet packet = packetSendAction.packet; +- if (packet.hasFinishListener()) { +- packet.onPacketDispatchFinish(player, null); ++ // Folia start - region threading - connection fixes ++ java.util.List queuedPackets = new java.util.ArrayList<>(); ++ // synchronise so that flushQueue does not poll values while the queue is being cleared ++ synchronized (this.pendingActions) { ++ Connection.WrappedConsumer consumer; ++ while ((consumer = this.pendingActions.poll()) != null) { ++ if (consumer instanceof Connection.PacketSendAction packetHolder) { ++ queuedPackets.add(packetHolder); + } + } + } +- this.pendingActions.clear(); ++ ++ for (Connection.PacketSendAction queuedPacket : queuedPackets) { ++ Packet packet = queuedPacket.packet; ++ if (packet.hasFinishListener()) { ++ packet.onPacketDispatchFinish(player, null); ++ } ++ } ++ // Folia end - region threading - connection fixes + } + + private static class InnerUtil { // Attempt to hide these methods from ProtocolLib, so it doesn't accidently pick them up. diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index d2f0a0755317f5fa9a1ccf7db346aa77fd287d80..b07df826a3028c14b48b09dbaeccc9078d7cc992 100644 +index 9a49f5271ec1d9de17632bfffe8309cb1ba0d8b1..c06bed93f6a701b1639c1cc334802e7b802431a5 100644 --- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java +++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -2,6 +2,7 @@ package net.minecraft.network.protocol; - - import com.mojang.logging.LogUtils; - import net.minecraft.network.PacketListener; -+import net.minecraft.server.level.ServerPlayer; - import org.slf4j.Logger; - - // CraftBukkit start -@@ -41,7 +42,7 @@ public class PacketUtils { +@@ -43,7 +43,7 @@ public class PacketUtils { public static void ensureRunningOnSameThread(Packet packet, T listener, BlockableEventLoop engine) throws RunningOnDifferentThreadException { if (!engine.isSameThread()) { @@ -10429,31 +10521,35 @@ index d2f0a0755317f5fa9a1ccf7db346aa77fd287d80..b07df826a3028c14b48b09dbaeccc907 + Runnable run = () -> { // Folia - region threading packetProcessing.push(listener); // Paper - detailed watchdog information try { // Paper - detailed watchdog information - if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerGamePacketListenerImpl && ((ServerGamePacketListenerImpl) listener).processedDisconnect)) return; // CraftBukkit, MC-142590 -@@ -66,7 +67,17 @@ public class PacketUtils { + if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerCommonPacketListenerImpl && ((ServerCommonPacketListenerImpl) listener).processedDisconnect)) return; // CraftBukkit, MC-142590 +@@ -77,7 +77,21 @@ public class PacketUtils { } // Paper end - detailed watchdog information - }); + }; // Folia start - region threading -+ ServerGamePacketListenerImpl actualListener = (ServerGamePacketListenerImpl)listener; + // ignore retired state, if removed then we don't want the packet to be handled -+ actualListener.player.getBukkitEntity().taskScheduler.schedule( -+ (ServerPlayer player) -> { -+ run.run(); -+ }, -+ null, -+ 1L -+ ); ++ if (listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ gamePacketListener.player.getBukkitEntity().taskScheduler.schedule( ++ (net.minecraft.server.level.ServerPlayer player) -> { ++ run.run(); ++ }, ++ null, 1L ++ ); ++ } else if (listener instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(run); ++ } else { ++ throw new UnsupportedOperationException("Unknown listener: " + listener); ++ } + // Folia end - region threading throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; // CraftBukkit start - SPIGOT-5477, MC-142590 - } else if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerGamePacketListenerImpl && ((ServerGamePacketListenerImpl) listener).processedDisconnect)) { + } else if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerCommonPacketListenerImpl && ((ServerCommonPacketListenerImpl) listener).processedDisconnect)) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 211408450ab4bf714860a52a9deff63e75ec20d1..99f1e6c72c734079dfc2c2a8b8093554e945fc6a 100644 +index a17160766eb15e8d11ddcce23747f8ab1923b676..3f283e1a5c181819b223c0f44cc5d8f274fd88a6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -242,7 +242,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; public Commands vanillaCommandDispatcher; -@@ -305,12 +305,40 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system -@@ -602,7 +630,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + public void tickChildren(BooleanSupplier shouldKeepTicking, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - region threading ++ final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); // Folia - regionised ticking ++ if (region == null) this.getPlayerList().getPlayers().forEach((entityplayer) -> { // Folia - region threading + entityplayer.connection.suspendFlushing(); + }); MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper - this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit + // Folia - region threading @@ -10938,7 +11043,7 @@ index 211408450ab4bf714860a52a9deff63e75ec20d1..99f1e6c72c734079dfc2c2a8b8093554 MinecraftTimings.commandFunctionsTimer.stopTiming(); // Spigot // Paper this.profiler.popPush("levels"); //Iterator iterator = this.getAllLevels().iterator(); // Paper - moved down -@@ -1503,7 +1624,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper @@ -10981,7 +11087,7 @@ index 211408450ab4bf714860a52a9deff63e75ec20d1..99f1e6c72c734079dfc2c2a8b8093554 this.profiler.push(() -> { return worldserver + " " + worldserver.dimension().location(); -@@ -1553,7 +1672,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop command = new java.util.concurrent.atomic.AtomicReference<>(s); // Paper diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index e2202389a2c4133a183cca59c4e909fc419379ab..18f438eec03cabc1614ab807081cff6b18fb09a8 100644 +index 5afeb59ff25fed2d565407acacffec8383398006..047e817eae19800d146970a3ab44913ea1d17c89 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -81,18 +81,18 @@ public class ChunkHolder { +@@ -81,7 +81,7 @@ public class ChunkHolder { public void onChunkAdd() { - // Paper start - optimise anyPlayerCloseEnoughForSpawning - long key = io.papermc.paper.util.MCUtil.getCoordinateKey(this.pos); -- this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); -- this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); -+ this.playersInMobSpawnRange = null; // Folia - region threading -+ this.playersInChunkTickRange = null; // Folia - region threading - // Paper end - optimise anyPlayerCloseEnoughForSpawning // Paper start - optimise chunk tick iteration if (this.needsBroadcastChanges()) { - this.chunkMap.needsChangeBroadcasting.add(this); + this.chunkMap.level.needsChangeBroadcasting.add(this); // Folia - region threading } // Paper end - optimise chunk tick iteration - // Paper start - optimise checkDespawn - LevelChunk chunk = this.getFullChunkNowUnchecked(); - if (chunk != null) { -- chunk.updateGeneralAreaCache(); -+ //chunk.updateGeneralAreaCache(); // Folia - region threading - } - // Paper end - optimise checkDespawn } -@@ -104,13 +104,13 @@ public class ChunkHolder { - // Paper end - optimise anyPlayerCloseEnoughForSpawning +@@ -89,7 +89,7 @@ public class ChunkHolder { + public void onChunkRemove() { // Paper start - optimise chunk tick iteration if (this.needsBroadcastChanges()) { - this.chunkMap.needsChangeBroadcasting.remove(this); + this.chunkMap.level.needsChangeBroadcasting.remove(this); // Folia - region threading } // Paper end - optimise chunk tick iteration - // Paper start - optimise checkDespawn - LevelChunk chunk = this.getFullChunkNowUnchecked(); - if (chunk != null) { -- chunk.removeGeneralAreaCache(); -+ //chunk.removeGeneralAreaCache(); // Folia - region threading - } - // Paper end - optimise checkDespawn - } -@@ -297,8 +297,8 @@ public class ChunkHolder { } +@@ -284,7 +284,7 @@ public class ChunkHolder { private void addToBroadcastMap() { -- org.spigotmc.AsyncCatcher.catchOp("ChunkHolder update"); + io.papermc.paper.util.TickThread.ensureTickThread(this.chunkMap.level, this.pos, "Asynchronous ChunkHolder update is not allowed"); - this.chunkMap.needsChangeBroadcasting.add(this); -+ io.papermc.paper.util.TickThread.ensureTickThread(this.chunkMap.level, this.pos, "Cannot update chunk holder asynchronously"); // Folia - region threading + this.chunkMap.level.needsChangeBroadcasting.add(this); // Folia - region threading } // Paper end - optimise chunk tick iteration diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac89812c15e 100644 +index 0c2617574e21037d94ac56ad08b490f9bca5c5af..a1cbf387c72482034eeee6be8a5c2228131601a9 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -147,21 +147,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -136,8 +136,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final AtomicInteger tickingGenerated; public final StructureTemplateManager structureTemplateManager; // Paper - rewrite chunk system private final String storageName; @@ -12561,123 +12653,57 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 private final Long2ByteMap chunkTypeCache; private final Long2LongMap chunkSaveCooldowns; private final Queue unloadQueue; - int viewDistance; -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper -- public final ReferenceOpenHashSet needsChangeBroadcasting = new ReferenceOpenHashSet<>(); -+ //public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper // Folia - region threading -+ //public final ReferenceOpenHashSet needsChangeBroadcasting = new ReferenceOpenHashSet<>(); // Folia - region threading - +@@ -146,13 +146,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper - rewrite chunk system - // Paper start - optimise checkDespawn - public static final int GENERAL_AREA_MAP_SQUARE_RADIUS = 40; - public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE = 16.0 * (GENERAL_AREA_MAP_SQUARE_RADIUS - 1); - public static final double GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE_SQUARED = GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE * GENERAL_AREA_MAP_ACCEPTABLE_SEARCH_RANGE; -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap; -+ //public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerGeneralAreaMap; // Folia - region threading - // Paper end - optimise checkDespawn // Paper start - distance maps -@@ -173,11 +173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - // inlined EnumMap, TrackingRange.TrackingRangeType - static final org.spigotmc.TrackingRange.TrackingRangeType[] TRACKING_RANGE_TYPES = org.spigotmc.TrackingRange.TrackingRangeType.values(); -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps; -- final int[] entityTrackerTrackRanges; -- public final int getEntityTrackerRange(final int ordinal) { -- return this.entityTrackerTrackRanges[ordinal]; -- } -+ // Folia - region threading - - private int convertSpigotRangeToVanilla(final int vanilla) { - return net.minecraft.server.MinecraftServer.getServer().getScaledTrackingDistance(vanilla); -@@ -191,8 +187,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // obviously this means a spawn range > 8 cannot be implemented - - // these maps are named after spigot's uses -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick -- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap; -+ //public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick // Folia - region threading -+ //public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap; // Folia - region threading - // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning +- private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); ++ //private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); // Folia - region threading void addPlayerToDistanceMaps(ServerPlayer player) { -@@ -200,40 +196,29 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated -- this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning -+ //this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Folia - region threading - // Paper start - per player mob spawning -- if (this.playerMobDistanceMap != null) { -- this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); -- } +- this.nearbyPlayers.addPlayer(player); + // Folia - region threading - // Paper end - per player mob spawning - // Paper start - use distance map to optimise entity tracker -- for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) { -- com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; -- int trackRange = this.entityTrackerTrackRanges[i]; -- -- trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); -- } -+ // Folia - region threading - // Paper end - use distance map to optimise entity tracker -- this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn -+ //this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn // Folia - region threading + this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader } - void removePlayerFromDistanceMaps(ServerPlayer player) { +@@ -160,16 +160,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); + // Note: players need to be explicitly added to distance maps before they can be updated +- this.nearbyPlayers.removePlayer(player); ++ // Folia - region threading this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader - - // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning -- this.playerMobSpawnMap.remove(player); -- this.playerChunkTickRangeMap.remove(player); -+ this.level.getCurrentWorldData().mobSpawnMap.remove(player); // Folia - region threading -+ //this.playerChunkTickRangeMap.remove(player); // Folia - region threading - // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning -- this.playerGeneralAreaMap.remove(player); // Paper - optimise checkDespawns -+ //this.playerGeneralAreaMap.remove(player); // Paper - optimise checkDespawns // Folia - region threading - // Paper start - per player mob spawning -- if (this.playerMobDistanceMap != null) { -- this.playerMobDistanceMap.remove(player); -- } +- this.playerMobSpawnMap.remove(player); // Paper - optimise chunk tick iteration + // Folia - region threading - // Paper end - per player mob spawning - // Paper start - use distance map to optimise tracker -- for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) { -- this.playerEntityTrackerTrackMaps[i].remove(player); -- } -+ // Folia - region threading - // Paper end - use distance map to optimise tracker } -@@ -242,21 +227,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + void updateMaps(ServerPlayer player) { + int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated +- this.nearbyPlayers.tickPlayer(player); ++ // Folia - region threading this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader -- this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning -+ //this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Folia - region threading - // Paper start - per player mob spawning -- if (this.playerMobDistanceMap != null) { -- this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); -- } -+ // Folia - region threading - // Paper end - per player mob spawning - // Paper start - use distance map to optimise entity tracker -- for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) { -- com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; -- int trackRange = this.entityTrackerTrackRanges[i]; -- -- trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); -- } -+ // Folia - region threading - // Paper end - use distance map to optimise entity tracker -- this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn -+ //this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn // Folia - region threading } // Paper end - // Paper start -@@ -294,8 +272,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -202,19 +202,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { + return null; // Paper - rewrite chunk system + } +- public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers; ++ //public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers; // Folia - region threading + // Paper end + // Paper start - optimise chunk tick iteration +- public final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet needsChangeBroadcasting = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); +- public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); ++ //public final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet needsChangeBroadcasting = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Folia - region threading ++ //public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); // Folia - region threading + // Paper end - optimise chunk tick iteration + + public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Paper - rewrite chunk system this.tickingGenerated = new AtomicInteger(); @@ -12688,161 +12714,26 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 this.chunkTypeCache = new Long2ByteOpenHashMap(); this.chunkSaveCooldowns = new Long2LongOpenHashMap(); this.unloadQueue = Queues.newConcurrentLinkedQueue(); -@@ -340,96 +318,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.setViewDistance(viewDistance); +@@ -259,15 +259,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.setServerViewDistance(viewDistance); // Paper start this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); - this.regionManagers.add(this.dataRegionManager); +- this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level); + //this.regionManagers.add(this.dataRegionManager); // Folia - region threading ++ //this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level); // Folia - region threading // Paper end -- this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper -+ //this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper // Folia - region threading - // Paper start - use distance map to optimise entity tracker -- this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length]; -- this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length]; -- -- org.spigotmc.SpigotWorldConfig spigotWorldConfig = this.level.spigotConfig; -- -- for (int ordinal = 0, len = TRACKING_RANGE_TYPES.length; ordinal < len; ++ordinal) { -- org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = TRACKING_RANGE_TYPES[ordinal]; -- int configuredSpigotValue; -- switch (trackingRangeType) { -- case PLAYER: -- configuredSpigotValue = spigotWorldConfig.playerTrackingRange; -- break; -- case ANIMAL: -- configuredSpigotValue = spigotWorldConfig.animalTrackingRange; -- break; -- case MONSTER: -- configuredSpigotValue = spigotWorldConfig.monsterTrackingRange; -- break; -- case MISC: -- configuredSpigotValue = spigotWorldConfig.miscTrackingRange; -- break; -- case OTHER: -- configuredSpigotValue = spigotWorldConfig.otherTrackingRange; -- break; -- case ENDERDRAGON: -- configuredSpigotValue = EntityType.ENDER_DRAGON.clientTrackingRange() * 16; -- break; -- default: -- throw new IllegalStateException("Missing case for enum " + trackingRangeType); -- } -- configuredSpigotValue = convertSpigotRangeToVanilla(configuredSpigotValue); -- -- int trackRange = (configuredSpigotValue >>> 4) + ((configuredSpigotValue & 15) != 0 ? 1 : 0); -- this.entityTrackerTrackRanges[ordinal] = trackRange; -- -- this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); -- } -+ // Folia - region threading - // Paper end - use distance map to optimise entity tracker - // Paper start - optimise ChunkMap#anyPlayerCloseEnoughForSpawning -- this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ)); -- if (playerChunk != null) { -- playerChunk.playersInChunkTickRange = newState; -- } -- }, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ)); -- if (playerChunk != null) { -- playerChunk.playersInChunkTickRange = newState; -- } -- }); -- this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ)); -- if (playerChunk != null) { -- playerChunk.playersInMobSpawnRange = newState; -- } -- }, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ)); -- if (playerChunk != null) { -- playerChunk.playersInMobSpawnRange = newState; -- } -- }); -+ // Folia - region threading -+ // Folia - region threading - // Paper end - optimise ChunkMap#anyPlayerCloseEnoughForSpawning - // Paper start - optimise checkDespawn -- this.playerGeneralAreaMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ); -- if (chunk != null) { -- chunk.updateGeneralAreaCache(newState); -- } -- }, -- (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState) -> { -- LevelChunk chunk = ChunkMap.this.level.getChunkSource().getChunkAtIfCachedImmediately(rangeX, rangeZ); -- if (chunk != null) { -- chunk.updateGeneralAreaCache(newState); -- } -- }); -+ // Folia - region threading - // Paper end - optimise checkDespawn } -@@ -456,49 +356,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }); + // Paper start + // always use accessor, so folia can override + public final io.papermc.paper.util.player.NearbyPlayers getNearbyPlayers() { +- return this.nearbyPlayers; ++ return this.level.getCurrentWorldData().getNearbyPlayers(); // Folia - region threading } + // Paper end -- // Paper start -- public void updatePlayerMobTypeMap(Entity entity) { -- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -- return; -- } -- int index = entity.getType().getCategory().ordinal(); -- -- final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = this.playerMobDistanceMap.getObjectsInRange(entity.chunkPosition()); -- if (inRange == null) { -- return; -- } -- final Object[] backingSet = inRange.getBackingSet(); -- for (int i = 0; i < backingSet.length; i++) { -- if (!(backingSet[i] instanceof final ServerPlayer player)) { -- continue; -- } -- ++player.mobCounts[index]; -- } -- } -- -- // Paper start - per player mob count backoff -- public void updateFailurePlayerMobTypeMap(int chunkX, int chunkZ, net.minecraft.world.entity.MobCategory mobCategory) { -- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -- return; -- } -- int idx = mobCategory.ordinal(); -- final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = this.playerMobDistanceMap.getObjectsInRange(chunkX, chunkZ); -- if (inRange != null) { -- final Object[] set = inRange.getBackingSet(); -- for (int i = 0; i < set.length; i++) { -- if (!(set[i] instanceof ServerPlayer serverPlayer)) { -- continue; -- } -- ++serverPlayer.mobBackoffCounts[idx]; -- } -- } -- } -- // Paper end - per player mob count backoff -- -- public int getMobCountNear(ServerPlayer entityPlayer, net.minecraft.world.entity.MobCategory mobCategory) { -- return entityPlayer.mobCounts[mobCategory.ordinal()] + entityPlayer.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff -- } -- // Paper end -+ // Folia - region threading - revert per player mob caps - - private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) { - double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8); -@@ -766,6 +624,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -595,6 +595,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper start // rets true if to prevent the entity from being added public static boolean checkDupeUUID(ServerLevel level, Entity entity) { @@ -12855,10 +12746,10 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode mode = level.paperConfig().entities.spawning.duplicateUuid.mode; if (mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.WARN && mode != io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DuplicateUUID.DuplicateUUIDMode.DELETE -@@ -1030,6 +894,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -848,6 +854,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) { + boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) { + // Folia start - region threading + if (true) { + java.util.List players = this.level.getLocalPlayers(); @@ -12891,65 +12782,84 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 + return false; + } + // Folia end - region threading - // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance - // tested and confirmed via System.nanoTime() - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange; -@@ -1075,7 +971,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + int chunkRange = level.spigotConfig.mobSpawnRange; + chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; + chunkRange = (chunkRange > 8) ? 8 : chunkRange; +@@ -859,7 +897,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (!this.distanceManager.hasPlayersNearby(chunkcoordintpair.toLong())) { + return false; + } else { +- Iterator iterator = this.playerMap.getAllPlayers().iterator(); ++ Iterator iterator = null; // Folia - region threading + + ServerPlayer entityplayer; + +@@ -891,7 +929,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return List.of(); } else { Builder builder = ImmutableList.builder(); -- Iterator iterator = this.playerMap.getPlayers(i).iterator(); +- Iterator iterator = this.playerMap.getAllPlayers().iterator(); + Iterator iterator = this.level.getLocalPlayers().iterator(); // Folia - region threading while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -1104,25 +1000,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -920,25 +958,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } void updatePlayerStatus(ServerPlayer player, boolean added) { - boolean flag1 = this.skipPlayer(player); - boolean flag2 = this.playerMap.ignoredOrUnknown(player); -- int i = SectionPos.blockToSectionCoord(player.getBlockX()); -- int j = SectionPos.blockToSectionCoord(player.getBlockZ()); + // Folia - region threading if (added) { -- this.playerMap.addPlayer(ChunkPos.asLong(i, j), player, flag1); +- this.playerMap.addPlayer(player, flag1); + // Folia - region threading this.updatePlayerPos(player); - if (!flag1) { - this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); - } + // Folia - region threading + + // Paper - handled by player chunk loader this.addPlayerToDistanceMaps(player); // Paper - distance maps } else { SectionPos sectionposition = player.getLastSectionPos(); -- this.playerMap.removePlayer(sectionposition.chunk().toLong(), player); +- this.playerMap.removePlayer(player); - if (!flag2) { - this.distanceManager.removePlayer(sectionposition, player); - } + // Folia - region threading -+ // Folia - region threading + this.removePlayerFromDistanceMaps(player); // Paper - distance maps - } + // Paper - handled by player chunk loader +@@ -953,41 +985,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } -@@ -1141,44 +1030,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void move(ServerPlayer player) { - // Paper - delay this logic for the entity tracker tick, no need to duplicate it +- ObjectIterator objectiterator = this.entityMap.values().iterator(); +- +- while (objectiterator.hasNext()) { +- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); +- +- if (playerchunkmap_entitytracker.entity == player) { +- playerchunkmap_entitytracker.updatePlayers(this.level.players()); +- } else { +- playerchunkmap_entitytracker.updatePlayer(player); +- } +- } ++ // Folia - region threading - entity tracker optimisations -- int i = SectionPos.blockToSectionCoord(player.getBlockX()); -- int j = SectionPos.blockToSectionCoord(player.getBlockZ()); - SectionPos sectionposition = player.getLastSectionPos(); - SectionPos sectionposition1 = SectionPos.of((EntityAccess) player); -- long k = sectionposition.chunk().toLong(); -- long l = sectionposition1.chunk().toLong(); - boolean flag = this.playerMap.ignored(player); - boolean flag1 = this.skipPlayer(player); - boolean flag2 = sectionposition.asLong() != sectionposition1.asLong(); -- ++ // Folia - region threading + - if (flag2 || flag != flag1) { -- this.updatePlayerPos(player); ++ if (true) { // Folia - region threading + this.updatePlayerPos(player); - if (!flag) { - this.distanceManager.removePlayer(sectionposition, player); - } @@ -12965,22 +12875,11 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 - if (flag && !flag1) { - this.playerMap.unIgnorePlayer(player); - } -- -- if (k != l) { -- this.playerMap.updatePlayer(k, l, player); -- } -- } -- -- int i1 = sectionposition.x(); -- int j1 = sectionposition.z(); -- int k1 = this.viewDistance + 1; -- int l1; -- int i2; -+ // Folia - region threading - none of this logic is relevant anymore thanks to the player chunk loader ++ // Folia - region threading - // Paper - replaced by PlayerChunkLoader - -@@ -1201,9 +1053,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper - replaced by PlayerChunkLoader + } +@@ -1018,9 +1022,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void addEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot // Paper start - ignore and warn about illegal addEntity calls instead of crashing server @@ -12992,7 +12891,7 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 return; } if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Delay adding to tracker until after list packets -@@ -1216,27 +1068,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1033,27 +1037,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (i != 0) { int j = entitytypes.updateInterval(); @@ -13004,9 +12903,9 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker - this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); -- playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players +- playerchunkmap_entitytracker.updatePlayers(this.level.players()); + // Folia - region threading -+ playerchunkmap_entitytracker.updatePlayers(this.level.getLocalPlayers()); // Paper - don't search all players // Folia - region threading ++ playerchunkmap_entitytracker.updatePlayers(this.level.getLocalPlayers()); // Folia - region threading if (entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; @@ -13019,7 +12918,7 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 - if (playerchunkmap_entitytracker1.entity != entityplayer) { - playerchunkmap_entitytracker1.updatePlayer(entityplayer); + // Folia start - region threading -+ for (Entity possible : this.level.getCurrentWorldData().getLocalEntities()) { ++ for (Entity possible : this.level.getCurrentWorldData().getLoadedEntities()) { + if (possible.tracker != null) { + possible.tracker.updatePlayer(entityplayer); } @@ -13028,7 +12927,7 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 } } -@@ -1250,16 +1100,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1067,16 +1069,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ServerPlayer entityplayer = (ServerPlayer) entity; this.updatePlayerStatus(entityplayer, false); @@ -13052,46 +12951,13 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 if (playerchunkmap_entitytracker1 != null) { playerchunkmap_entitytracker1.broadcastRemoved(); -@@ -1269,25 +1119,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - // Paper start - optimised tracker - private final void processTrackQueue() { -- this.level.timings.tracker1.startTiming(); -- try { -- for (TrackedEntity tracker : this.entityMap.values()) { -- // update tracker entry -- tracker.updatePlayers(tracker.entity.getPlayersInTrackRange()); -- } -- } finally { -- this.level.timings.tracker1.stopTiming(); -- } -- -- -- this.level.timings.tracker2.startTiming(); -- try { -- for (TrackedEntity tracker : this.entityMap.values()) { -- tracker.serverEntity.sendChanges(); -+ // Folia start - region threading -+ List players = this.level.getLocalPlayers(); // Folia - region threading -+ for (Entity entity : this.level.getCurrentWorldData().getLocalEntities()) { -+ TrackedEntity tracker = entity.tracker; -+ if (tracker == null) { -+ continue; - } -- } finally { -- this.level.timings.tracker2.stopTiming(); -+ tracker.updatePlayers(players); -+ tracker.removeNonTickThreadPlayers(); -+ tracker.serverEntity.sendChanges(); - } -+ // Folia end - region threading +@@ -1084,54 +1086,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + entity.tracker = null; // Paper - We're no longer tracked } - // Paper end - optimised tracker -@@ -1298,51 +1141,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return; - } - // Paper end - optimized tracker +- protected void tick() { +- // Paper - replaced by PlayerChunkLoader +- - List list = Lists.newArrayList(); - List list1 = this.level.players(); - ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -13118,8 +12984,18 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 - - if (flag || this.distanceManager.inEntityTickingRange(sectionposition1.chunk().toLong())) { - playerchunkmap_entitytracker.serverEntity.sendChanges(); -- } -- } ++ // Folia start - region threading - replace entity tracking ticking ++ private void foliaEntityTrackerTick() { ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.level.getCurrentWorldData(); ++ io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = worldData.getNearbyPlayers(); ++ for (Entity entity : worldData.getLoadedEntities()) { ++ TrackedEntity tracker = entity.tracker; ++ if (tracker == null) { ++ continue; + } ++ tracker.tick(nearbyPlayers.getChunk(entity.chunkPosition())); ++ tracker.serverEntity.sendChanges(); + } - level.timings.tracker1.stopTiming(); // Paper - - if (!list.isEmpty()) { @@ -13129,11 +13005,20 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 - while (objectiterator.hasNext()) { - playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); - playerchunkmap_entitytracker.updatePlayers(list); -- } ++ // process unloads ++ for (Entity entity : worldData.takeTrackingUnloads()) { ++ TrackedEntity tracker = entity.tracker; ++ if (tracker == null) { ++ continue; + } - level.timings.tracker2.stopTiming(); // Paper -- } -+ // Folia - region threading ++ tracker.clearPlayers(); + } ++ } ++ // Folia end - region threading - replace entity tracking ticking ++ protected void tick() { ++ this.foliaEntityTrackerTick(); // Folia - region threading - replace entity tracking ticking } public void broadcast(Entity entity, Packet packet) { @@ -13142,7 +13027,7 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 if (playerchunkmap_entitytracker != null) { playerchunkmap_entitytracker.broadcast(packet); -@@ -1351,7 +1155,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1140,7 +1123,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } protected void broadcastAndSend(Entity entity, Packet packet) { @@ -13151,54 +13036,49 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 if (playerchunkmap_entitytracker != null) { playerchunkmap_entitytracker.broadcastAndSend(packet); -@@ -1459,41 +1263,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.lastSectionPos = SectionPos.of((EntityAccess) entity); - } - -- // Paper start - use distance map to optimise tracker -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet lastTrackerCandidates; -- -- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet oldTrackerCandidates = this.lastTrackerCandidates; -- this.lastTrackerCandidates = newTrackerCandidates; -- -- if (newTrackerCandidates != null) { -- Object[] rawData = newTrackerCandidates.getBackingSet(); -- for (int i = 0, len = rawData.length; i < len; ++i) { -- Object raw = rawData[i]; -- if (!(raw instanceof ServerPlayer)) { -- continue; -- } -- ServerPlayer player = (ServerPlayer)raw; -- this.updatePlayer(player); -- } -- } -- -- if (oldTrackerCandidates == newTrackerCandidates) { -- // this is likely the case. -- // means there has been no range changes, so we can just use the above for tracking. -- return; -- } -- -- // stuff could have been removed, so we need to check the trackedPlayers set -- // for players that were removed -- -- for (ServerPlayerConnection conn : this.seenBy.toArray(new ServerPlayerConnection[0])) { // avoid CME -- if (newTrackerCandidates == null || !newTrackerCandidates.contains(conn.getPlayer())) { -- this.updatePlayer(conn.getPlayer()); -- } -- } -- } -- // Paper end - use distance map to optimise tracker -+ // Folia - region threading - - public boolean equals(Object object) { - return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false; -@@ -1540,6 +1310,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1281,6 +1264,78 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } + // Folia start - region threading ++ private int lastChunkUpdate = -1; ++ private io.papermc.paper.util.player.NearbyPlayers.TrackedChunk lastTrackedChunk; ++ public void tick(io.papermc.paper.util.player.NearbyPlayers.TrackedChunk chunk) { ++ if (chunk == null) { ++ this.clearPlayers(); ++ return; ++ } ++ ++ com.destroystokyo.paper.util.maplist.ReferenceList players = ++ chunk.getPlayers(io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.VIEW_DISTANCE); ++ ++ if (players == null) { ++ this.clearPlayers(); ++ return; ++ } ++ ++ int lastChunkUpdate = this.lastChunkUpdate; ++ int currChunkUpdate = chunk.getUpdateCount(); ++ io.papermc.paper.util.player.NearbyPlayers.TrackedChunk lastTrackedChunk = this.lastTrackedChunk; ++ this.lastChunkUpdate = currChunkUpdate; ++ this.lastTrackedChunk = chunk; ++ ++ for (int i = 0, len = players.size(); i < len; ++i) { ++ ServerPlayer player = players.getUnchecked(i); ++ this.updatePlayer(player); ++ } ++ ++ if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) { ++ // need to purge any players possible not in the chunk list ++ for (ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) { ++ ServerPlayer player = conn.getPlayer(); ++ if (!players.contains(player)) { ++ this.removePlayer(player); ++ } ++ } ++ } ++ } ++ + public void removeNonTickThreadPlayers() { + boolean foundToRemove = false; + for (ServerPlayerConnection conn : this.seenBy) { @@ -13219,11 +13099,23 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 + } + } + } ++ ++ public void clearPlayers() { ++ this.lastChunkUpdate = -1; ++ this.lastTrackedChunk = null; ++ if (this.seenBy.isEmpty()) { ++ return; ++ } ++ for (ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) { ++ ServerPlayer player = conn.getPlayer(); ++ this.removePlayer(player); ++ } ++ } + // Folia end - region threading public void updatePlayer(ServerPlayer player) { org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot -@@ -1563,9 +1355,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1300,9 +1355,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } // Paper end - check Y @@ -13235,36 +13127,33 @@ index 65d947df910d60f478e7a449eb161e5105e2c0c9..475edb726964f3757957474856c61ac8 // CraftBukkit start - respect vanish API - if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { -+ if (flag && !io.papermc.paper.util.TickThread.isTickThreadFor(player) || !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Folia - region threading ++ if (flag && (!io.papermc.paper.util.TickThread.isTickThreadFor(player) || !player.getBukkitEntity().canSee(this.entity.getBukkitEntity()))) { // Folia - region threading flag = false; } // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index ae4a4710ba07614be42cdcbf52cee04cfa08466b..e17baf04afe5140427df40450a6e0c116d1236f5 100644 +index 55f96545d6db95e3e657502a7910d96fded1113e..b39dd5a11a34407244666d8b9c1e775d6ff90fff 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -194,14 +194,14 @@ public abstract class DistanceManager { +@@ -192,11 +192,11 @@ public abstract class DistanceManager { + } + public int getNaturalSpawnChunkCount() { - // Paper start - use distance map to implement - // note: this is the spawn chunk count -- return this.chunkMap.playerChunkTickRangeMap.size(); -+ return this.chunkMap.level.getCurrentWorldData().mobSpawnMap.size(); // Folia - region threading - // Paper end - use distance map to implement +- return this.chunkMap.playerMobSpawnMap.size(); // Paper - optimise chunk tick iteration ++ return this.chunkMap.level.getCurrentWorldData().mobSpawnMap.size(); // Paper - optimise chunk tick iteration // Folia - region threading } public boolean hasPlayersNearby(long chunkPos) { - // Paper start - use distance map to implement - // note: this is the is spawn chunk method -- return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(chunkPos) != null; -+ return this.chunkMap.level.getCurrentWorldData().mobSpawnMap.getObjectsInRange(chunkPos) != null; // Folia - region threading - // Paper end - use distance map to implement +- return this.chunkMap.playerMobSpawnMap.getObjectsInRange(chunkPos) != null; // Paper - optimise chunk tick iteration ++ return this.chunkMap.level.getCurrentWorldData().mobSpawnMap.getObjectsInRange(chunkPos) != null; // Paper - optimise chunk tick iteration // Folia - region threading } + public String getDebugStatus() { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b5f502681 100644 +index 17b6925b46f8386dcfc561483693de516465ec12..18735dbd0d2bae1576d2bdb7402d98e9affbd599 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -61,73 +61,42 @@ public class ServerChunkCache extends ChunkSource { +@@ -60,73 +60,42 @@ public class ServerChunkCache extends ChunkSource { public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; public final ChunkMap chunkMap; private final DimensionDataStorage dataStorage; @@ -13319,12 +13208,12 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b - } finally { - this.loadedChunkMapSeqLock.releaseWrite(); - } -- ++ } // Folia - region threading + - // rewrite cache if we have to - // we do this since we also cache null chunks - int cacheKey = getChunkCacheKey(chunk.locX, chunk.locZ); -+ } // Folia - region threading - +- - LevelChunk cachedChunk = this.lastLoadedChunks[cacheKey]; - if (cachedChunk != null && cachedChunk.coordinateKey == chunk.coordinateKey) { - this.lastLoadedChunks[cacheKey] = null; @@ -13350,7 +13239,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b } public final LevelChunk getChunkAtIfLoadedMainThreadNoCache(int x, int z) { -@@ -164,8 +133,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -163,8 +132,7 @@ public class ServerChunkCache extends ChunkSource { this.distanceManager.removeTicket(ticketType, chunkPos, ticketLevel, identifier); } @@ -13360,7 +13249,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b // Paper end public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory) { -@@ -239,26 +207,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -238,26 +206,7 @@ public class ServerChunkCache extends ChunkSource { public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) { long k = ChunkPos.asLong(x, z); @@ -13388,7 +13277,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b } // Paper end -@@ -332,6 +281,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -331,6 +280,7 @@ public class ServerChunkCache extends ChunkSource { } public CompletableFuture> getChunkFuture(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { @@ -13396,7 +13285,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b boolean flag1 = io.papermc.paper.util.TickThread.isTickThread(); // Paper - rewrite chunk system CompletableFuture completablefuture; -@@ -509,10 +459,11 @@ public class ServerChunkCache extends ChunkSource { +@@ -508,10 +458,11 @@ public class ServerChunkCache extends ChunkSource { } private void tickChunks() { @@ -13410,42 +13299,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b boolean flag = this.level.isDebug(); if (flag) { -@@ -520,9 +471,11 @@ public class ServerChunkCache extends ChunkSource { - } else { - // Paper start - optimize isOutisdeRange - ChunkMap playerChunkMap = this.chunkMap; -- for (ServerPlayer player : this.level.players) { -+ // Folia - region threading -+ -+ for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading - if (!player.affectsSpawning || player.isSpectator()) { -- playerChunkMap.playerMobSpawnMap.remove(player); -+ regionizedWorldData.mobSpawnMap.remove(player); // Folia - region threading - continue; - } - -@@ -535,8 +488,9 @@ public class ServerChunkCache extends ChunkSource { - - com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange); - event.callEvent(); -- if (event.isCancelled() || event.getSpawnRadius() < 0 || playerChunkMap.playerChunkTickRangeMap.getLastViewDistance(player) == -1) { -- playerChunkMap.playerMobSpawnMap.remove(player); -+ if (event.isCancelled() || event.getSpawnRadius() < 0) { // Folia - region threading -+ player.lastEntitySpawnRadiusSquared = -1.0; player.playerNaturallySpawnedEvent = null; // Folia - region threading -+ regionizedWorldData.mobSpawnMap.remove(player); // Folia - region threading - continue; - } - -@@ -544,7 +498,7 @@ public class ServerChunkCache extends ChunkSource { - int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); - -- playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); -+ regionizedWorldData.mobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); // Folia - region threading - player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning - player.playerNaturallySpawnedEvent = event; - } -@@ -554,36 +508,19 @@ public class ServerChunkCache extends ChunkSource { +@@ -522,7 +473,7 @@ public class ServerChunkCache extends ChunkSource { gameprofilerfiller.push("pollingChunks"); int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); @@ -13454,71 +13308,85 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b gameprofilerfiller.push("naturalSpawnCount"); this.level.timings.countNaturalMobs.startTiming(); // Paper - timings - int l = this.distanceManager.getNaturalSpawnChunkCount(); - // Paper start - per player mob spawning - NaturalSpawner.SpawnState spawnercreature_d; // moved down -- if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled -- // re-set mob counts -- for (ServerPlayer player : this.level.players) { -- // Paper start - per player mob spawning backoff -- for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { -- player.mobCounts[ii] = 0; -- -- int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm? -- if (newBackoff < 0) { -- newBackoff = 0; -- } -- player.mobBackoffCounts[ii] = newBackoff; -- } -- // Paper end - per player mob spawning backoff -- } +@@ -544,14 +495,14 @@ public class ServerChunkCache extends ChunkSource { + } + // Paper end - per player mob spawning backoff + } - spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true); -- } else { -- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false); -- } -- // Paper end -+ // Folia start - threaded regions - revert per-player mob caps -+ spawnercreature_d = this.spawnFriendlies || this.spawnEnemies ? NaturalSpawner.createState(l, regionizedWorldData.getLocalEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap)) : null; // Folia - region threading -+ // Folia end - threaded regions - revert per-player mob caps ++ spawnercreature_d = NaturalSpawner.createState(l, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading + } else { +- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ spawnercreature_d = NaturalSpawner.createState(l, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading + } + // Paper end this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings - this.lastSpawnState = spawnercreature_d; + regionizedWorldData.lastSpawnState = spawnercreature_d; // Folia - region threading gameprofilerfiller.popPush("filteringLoadedChunks"); - // Paper - moved down - this.level.timings.chunkTicks.startTiming(); // Paper -@@ -591,18 +528,18 @@ public class ServerChunkCache extends ChunkSource { - // Paper - moved down + // Paper - optimise chunk tick iteration + // Paper - optimise chunk tick iteration +@@ -560,13 +511,13 @@ public class ServerChunkCache extends ChunkSource { + // Paper - optimise chunk tick iteration gameprofilerfiller.popPush("spawnAndTick"); - boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !regionizedWorldData.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading - // Paper - only shuffle if per-player mob spawning is disabled - // Paper - moved natural spawn event up + // Paper start - optimise chunk tick iteration + ChunkMap playerChunkMap = this.chunkMap; +- for (ServerPlayer player : this.level.players) { ++ for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading + if (!player.affectsSpawning || player.isSpectator()) { +- playerChunkMap.playerMobSpawnMap.remove(player); ++ regionizedWorldData.mobSpawnMap.remove(player); // Folia - region threading + player.playerNaturallySpawnedEvent = null; + player.lastEntitySpawnRadiusSquared = -1.0; + continue; +@@ -582,7 +533,7 @@ public class ServerChunkCache extends ChunkSource { + com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange); + event.callEvent(); + if (event.isCancelled() || event.getSpawnRadius() < 0) { +- playerChunkMap.playerMobSpawnMap.remove(player); ++ regionizedWorldData.mobSpawnMap.remove(player); // Folia - region threading + player.playerNaturallySpawnedEvent = null; + player.lastEntitySpawnRadiusSquared = -1.0; + continue; +@@ -592,7 +543,7 @@ public class ServerChunkCache extends ChunkSource { + int chunkX = io.papermc.paper.util.CoordinateUtils.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.CoordinateUtils.getChunkCoordinate(player.getZ()); - // Paper start - optimise chunk tick iteratio +- playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); ++ regionizedWorldData.mobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); // Folia - region threading + player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning + player.playerNaturallySpawnedEvent = event; + } +@@ -603,10 +554,10 @@ public class ServerChunkCache extends ChunkSource { + io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = this.chunkMap.getNearbyPlayers(); // Paper - optimise chunk tick iteration Iterator iterator1; -- if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { -- iterator1 = this.entityTickingChunks.iterator(); -+ if (true) { // Folia - region threading - revert per player mob caps, except for this - WTF are they doing? -+ iterator1 = regionizedWorldData.getEntityTickingChunks().iterator(); // Folia - region threading + if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { +- iterator1 = this.tickingChunks.iterator(); ++ iterator1 = regionizedWorldData.getTickingChunks().iterator(); // Folia - region threading } else { -- iterator1 = this.entityTickingChunks.unsafeIterator(); -- List shuffled = Lists.newArrayListWithCapacity(this.entityTickingChunks.size()); -+ iterator1 = regionizedWorldData.getEntityTickingChunks().unsafeIterator(); // Folia - region threading -+ List shuffled = Lists.newArrayListWithCapacity(regionizedWorldData.getEntityTickingChunks().size()); // Folia - region threading +- iterator1 = this.tickingChunks.unsafeIterator(); +- List shuffled = Lists.newArrayListWithCapacity(this.tickingChunks.size()); ++ iterator1 = regionizedWorldData.getTickingChunks().unsafeIterator(); // Folia - region threading ++ List shuffled = Lists.newArrayListWithCapacity(regionizedWorldData.getTickingChunks().size()); // Folia - region threading while (iterator1.hasNext()) { shuffled.add(iterator1.next()); } -@@ -652,14 +589,19 @@ public class ServerChunkCache extends ChunkSource { - // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded - gameprofilerfiller.popPush("broadcast"); - this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing +@@ -673,17 +624,21 @@ public class ServerChunkCache extends ChunkSource { + // Paper - optimise chunk tick iteration + this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing + // Paper start - optimise chunk tick iteration - if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) { -- ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); +- it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet copy = this.chunkMap.needsChangeBroadcasting.clone(); - this.chunkMap.needsChangeBroadcasting.clear(); - for (ChunkHolder holder : copy) { +- holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded +- if (holder.needsBroadcastChanges()) { +- // I DON'T want to KNOW what DUMB plugins might be doing. +- this.chunkMap.needsChangeBroadcasting.add(holder); + // Folia start - region threading + if (!this.level.needsChangeBroadcasting.isEmpty()) { + for (Iterator iterator = this.level.needsChangeBroadcasting.iterator(); iterator.hasNext();) { @@ -13527,28 +13395,17 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b + continue; + } + // don't need to worry about chunk holder remove, as that can only be done by this tick thread -+ // Folia end - region threading - holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded -- if (holder.needsBroadcastChanges()) { -+ if (!holder.needsBroadcastChanges()) { // Folia - region threading - // I DON'T want to KNOW what DUMB plugins might be doing. -- this.chunkMap.needsChangeBroadcasting.add(holder); -+ iterator.remove(); // Folia - region threading ++ holder.broadcastChanges(holder.getFullChunkNowUnchecked()); ++ if (!holder.needsBroadcastChanges()) { ++ iterator.remove(); } } } -@@ -667,8 +609,8 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.pop(); - // Paper end - use set of chunks requiring updates, rather than iterating every single one loaded - // Paper start - controlled flush for entity tracker packets -- List disabledFlushes = new java.util.ArrayList<>(this.level.players.size()); -- for (ServerPlayer player : this.level.players) { -+ List disabledFlushes = new java.util.ArrayList<>(regionizedWorldData.getLocalPlayers().size()); // Folia - region threading -+ for (ServerPlayer player : regionizedWorldData.getLocalPlayers()) { // Folia - region threading - net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection; - if (connection != null) { - connection.connection.disableAutomaticFlush(); -@@ -741,14 +683,19 @@ public class ServerChunkCache extends ChunkSource { ++ // Folia end - region threading + // Paper end - optimise chunk tick iteration + this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing + // Paper - optimise chunk tick iteration +@@ -747,14 +702,19 @@ public class ServerChunkCache extends ChunkSource { @Override public void onLightUpdate(LightLayer type, SectionPos pos) { @@ -13570,7 +13427,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b } public void addRegionTicket(TicketType ticketType, ChunkPos pos, int radius, T argument) { -@@ -820,7 +767,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -826,7 +786,8 @@ public class ServerChunkCache extends ChunkSource { @Nullable @VisibleForDebug public NaturalSpawner.SpawnState getLastSpawnState() { @@ -13580,7 +13437,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b } public void removeTicketsOnClosing() { -@@ -853,8 +801,43 @@ public class ServerChunkCache extends ChunkSource { +@@ -859,8 +820,43 @@ public class ServerChunkCache extends ChunkSource { return ServerChunkCache.this.mainThread; } @@ -13624,7 +13481,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b ServerChunkCache.this.level.getProfiler().incrementCounter("runTask"); super.doRunTask(task); } -@@ -862,10 +845,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -868,10 +864,15 @@ public class ServerChunkCache extends ChunkSource { @Override // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { @@ -13642,7 +13499,7 @@ index acbcdc8cb1523044b1657e03a141fae6389a3686..af35fd63b090aa3d89bc60cb9cb7694b } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e93795c38 100644 +index 868951dc21aff541765b1f58f08cdf3c47446d25..8b41da9d1f43340b6ba3812a93f681419d0d7cd8 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -192,36 +192,35 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -13691,7 +13548,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) public static Throwable getAddToWorldStackTrace(Entity entity) { final Throwable thr = new Throwable(entity + " Added to world at " + new java.util.Date()); -@@ -257,6 +256,37 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -257,6 +256,36 @@ public class ServerLevel extends Level implements WorldGenLevel { ServerChunkCache chunkProvider = this.getChunkSource(); @@ -13700,7 +13557,6 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e + if (!io.papermc.paper.util.TickThread.isTickThreadFor(this, minChunkX, minChunkZ, maxChunkX, maxChunkZ)) { + return false; + } -+ // Folia end - region threading + + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { + for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { @@ -13713,7 +13569,6 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e + return true; + } + -+ // Folia start - region threading + public final boolean isAreaLoaded(final BlockPos center, final int radius) { + int minX = (center.getX() - radius) >> 4; + int minZ = (center.getZ() - radius) >> 4; @@ -13724,60 +13579,53 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e + } + + public final boolean isAreaLoaded(final int minChunkX, final int minChunkZ, final int maxChunkX, final int maxChunkZ) { ++ // Folia end - region threading + ServerChunkCache chunkProvider = this.getChunkSource(); + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { if (chunkProvider.getChunkAtIfLoadedImmediately(cx, cz) == null) { -@@ -267,6 +297,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - - return true; - } -+ // Folia end - region threading - - public final void loadChunksAsync(BlockPos pos, int radiusBlocks, - ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, -@@ -563,83 +594,60 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -565,14 +594,14 @@ public class ServerLevel extends Level implements WorldGenLevel { } // Paper end - -- // Paper start - optimise checkDespawn -- public final List playersAffectingSpawning = new java.util.ArrayList<>(); -- // Paper end - optimise checkDespawn -- // Paper start - optimise get nearest players for entity AI -- @Override -- public final ServerPlayer getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, @Nullable LivingEntity source, -- double centerX, double centerY, double centerZ) { -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby; -- nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4); -- -- if (nearby == null) { -- return null; -- } -- -- Object[] backingSet = nearby.getBackingSet(); -- -- double closestDistanceSquared = Double.MAX_VALUE; -- ServerPlayer closest = null; -- -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- Object _player = backingSet[i]; -- if (!(_player instanceof ServerPlayer)) { -- continue; -- } -- ServerPlayer player = (ServerPlayer)_player; -- -- double distanceSquared = player.distanceToSqr(centerX, centerY, centerZ); -- if (distanceSquared < closestDistanceSquared && condition.test(source, player)) { -- closest = player; -- closestDistanceSquared = distanceSquared; -- } -- } -- -- return closest; + // Paper start - lag compensation +- private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT; + // Folia - region threading -+ -+ // Folia start - regionised ticking + + public long getLagCompensationTick() { +- return this.lagCompensationTick; ++ return this.getCurrentWorldData().getLagCompensationTick(); // Folia - region threading + } + + public void updateLagCompensationTick() { +- this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L)); ++ throw new UnsupportedOperationException(); // Folia - region threading + } + // Paper end - lag compensation + // Paper start - optimise nearby player retrieval +@@ -619,7 +648,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + ServerPlayer nearest = null; + double nearestDist = Double.MAX_VALUE; + +- for (ServerPlayer player : this.players()) { ++ for (ServerPlayer player : this.getLocalPlayers()) { // Folia - region threading + double dist = player.distanceToSqr(x, y, z); + if (dist >= nearestDist) { + continue; +@@ -675,7 +704,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + + return nearest; + } else { +- return this.getNearestEntity(this.players(), targetPredicate, entity, x, y, z); ++ return this.getNearestEntity(this.getLocalPlayers(), targetPredicate, entity, x, y, z); // Folia - region threading + } + } + +@@ -684,6 +713,58 @@ public class ServerLevel extends Level implements WorldGenLevel { + return this.getNearestPlayer(targetPredicate, null, x, y, z); + } + // Paper end - optimise nearby player retrieval ++ // Folia start - region threading + public final io.papermc.paper.threadedregions.TickRegions tickRegions = new io.papermc.paper.threadedregions.TickRegions(); + public final io.papermc.paper.threadedregions.ThreadedRegionizer regioniser; + { @@ -13790,79 +13638,49 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e + this, + this.tickRegions + ); - } ++ } + public final io.papermc.paper.threadedregions.RegionizedTaskQueue.WorldRegionTaskData taskQueueRegionData = new io.papermc.paper.threadedregions.RegionizedTaskQueue.WorldRegionTaskData(this); + public static final int WORLD_INIT_NOT_CHECKED = 0; + public static final int WORLD_INIT_CHECKING = 1; + public static final int WORLD_INIT_CHECKED = 2; + public final java.util.concurrent.atomic.AtomicInteger checkInitialised = new java.util.concurrent.atomic.AtomicInteger(WORLD_INIT_NOT_CHECKED); + public ChunkPos randomSpawnSelection; - -- @Override -- public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, LivingEntity entityliving) { -- return this.getNearestPlayer(pathfindertargetcondition, entityliving, entityliving.getX(), entityliving.getY(), entityliving.getZ()); -- } ++ + public static final record PendingTeleport(Entity.EntityTreeNode rootVehicle, Vec3 to) {} + private final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet pendingTeleports = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); - -- @Override -- public Player getNearestPlayer(net.minecraft.world.entity.ai.targeting.TargetingConditions pathfindertargetcondition, -- double d0, double d1, double d2) { -- return this.getNearestPlayer(pathfindertargetcondition, null, d0, d1, d2); ++ + public void pushPendingTeleport(final PendingTeleport teleport) { + synchronized (this.pendingTeleports) { + this.pendingTeleports.add(teleport); + } - } - -- @Override -- public List getNearbyPlayers(net.minecraft.world.entity.ai.targeting.TargetingConditions condition, LivingEntity source, AABB axisalignedbb) { -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby; -- double centerX = (axisalignedbb.maxX + axisalignedbb.minX) * 0.5; -- double centerZ = (axisalignedbb.maxZ + axisalignedbb.minZ) * 0.5; -- nearby = this.getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(Mth.floor(centerX) >> 4, Mth.floor(centerZ) >> 4); -- -- List ret = new java.util.ArrayList<>(); -- -- if (nearby == null) { -- return ret; ++ } ++ + public boolean removePendingTeleport(final PendingTeleport teleport) { + synchronized (this.pendingTeleports) { + return this.pendingTeleports.remove(teleport); - } ++ } + } - -- Object[] backingSet = nearby.getBackingSet(); -- -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- Object _player = backingSet[i]; -- if (!(_player instanceof ServerPlayer)) { -- continue; -- } -- ServerPlayer player = (ServerPlayer)_player; ++ + public List removeAllRegionTeleports() { + final List ret = new ArrayList<>(); - -- if (axisalignedbb.contains(player.getX(), player.getY(), player.getZ()) && condition.test(source, player)) { -- ret.add(player); ++ + synchronized (this.pendingTeleports) { -+ for (final Iterator iterator = this.pendingTeleports.iterator(); iterator.hasNext();) { ++ for (final Iterator iterator = this.pendingTeleports.iterator(); iterator.hasNext(); ) { + final PendingTeleport pendingTeleport = iterator.next(); + if (io.papermc.paper.util.TickThread.isTickThreadFor(this, pendingTeleport.to())) { + ret.add(pendingTeleport); + iterator.remove(); + } - } - } - - return ret; - } -- // Paper end - optimise get nearest players for entity AI -+ // Folia end - regionised ticking ++ } ++ } ++ ++ return ret; ++ } ++ // Folia end - region threading // Add env and gen to constructor, IWorldDataServer -> WorldDataServer public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -652,13 +660,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -696,13 +777,13 @@ public class ServerLevel extends Level implements WorldGenLevel { this.convertable = convertable_conversionsession; this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile()); // CraftBukkit end @@ -13882,7 +13700,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e this.dragonParts = new Int2ObjectOpenHashMap(); this.tickTime = flag1; this.server = minecraftserver; -@@ -697,7 +705,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -741,7 +822,7 @@ public class ServerLevel extends Level implements WorldGenLevel { }); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); this.portalForcer = new PortalForcer(this); @@ -13890,8 +13708,8 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e + //this.updateSkyBrightness(); // Folia - region threading - delay until first tick this.prepareWeather(); this.getWorldBorder().setAbsoluteMaxSize(minecraftserver.getAbsoluteMaxWorldSize()); - this.raids = (Raids) this.getDataStorage().computeIfAbsent((nbttagcompound) -> { -@@ -732,7 +740,14 @@ public class ServerLevel extends Level implements WorldGenLevel { + this.raids = (Raids) this.getDataStorage().computeIfAbsent(Raids.factory(this), Raids.getFileId(this.dimensionTypeRegistration())); +@@ -768,7 +849,14 @@ public class ServerLevel extends Level implements WorldGenLevel { this.chunkTaskScheduler = new io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler(this, io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.workerThreads); // Paper - rewrite chunk system this.entityLookup = new io.papermc.paper.chunk.system.entity.EntityLookup(this, new EntityCallbacks()); // Paper - rewrite chunk system @@ -13906,22 +13724,13 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // Paper start @Override -@@ -765,55 +780,31 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -801,47 +889,30 @@ public class ServerLevel extends Level implements WorldGenLevel { return this.structureManager; } - public void tick(BooleanSupplier shouldKeepTicking) { -- // Paper start - optimise checkDespawn -- this.playersAffectingSpawning.clear(); -- for (ServerPlayer player : this.players) { -- if (net.minecraft.world.entity.EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) { -- this.playersAffectingSpawning.add(player); -- } -- } -- // Paper end - optimise checkDespawn + public void tick(BooleanSupplier shouldKeepTicking, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking + final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking -+ // Folia - region threading ProfilerFiller gameprofilerfiller = this.getProfiler(); - this.handlingTick = true; @@ -13946,8 +13755,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e - this.setDayTime(this.getDayTime() + event.getSkipAmount()); - } - } -+ if (region == null) this.tickSleep(); // Folia - region threading - +- - if (!event.isCancelled()) { - this.wakeUpAllPlayers(); - } @@ -13956,7 +13764,8 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e - this.resetWeatherCycle(); - } - } -- ++ if (region == null) this.tickSleep(); // Folia - region threading + - this.updateSkyBrightness(); + if (region == null) this.updateSkyBrightness(); // Folia - region threading this.tickTime(); @@ -13974,7 +13783,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e gameprofilerfiller.pop(); } timings.scheduledBlocks.stopTiming(); // Paper -@@ -830,7 +821,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -858,7 +929,7 @@ public class ServerLevel extends Level implements WorldGenLevel { timings.doSounds.startTiming(); // Spigot this.runBlockEvents(); timings.doSounds.stopTiming(); // Spigot @@ -13983,7 +13792,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e gameprofilerfiller.pop(); boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players -@@ -842,20 +833,30 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -870,20 +941,30 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.push("entities"); timings.tickEntities.startTiming(); // Spigot if (this.dragonFight != null) { @@ -14015,7 +13824,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e gameprofilerfiller.pop(); if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list Entity entity1 = entity.getVehicle(); -@@ -886,6 +887,31 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -914,6 +995,31 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.pop(); } @@ -14047,7 +13856,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e @Override public boolean shouldTickBlocksAt(long chunkPos) { // Paper start - replace player chunk loader system -@@ -896,11 +922,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -924,11 +1030,12 @@ public class ServerLevel extends Level implements WorldGenLevel { protected void tickTime() { if (this.tickTime) { @@ -14064,7 +13873,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e this.setDayTime(this.levelData.getDayTime() + 1L); } -@@ -929,15 +956,23 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -957,15 +1064,23 @@ public class ServerLevel extends Level implements WorldGenLevel { private void wakeUpAllPlayers() { this.sleepStatus.removeAllSleepers(); (this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> { // CraftBukkit - decompile error @@ -14091,7 +13900,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e ChunkPos chunkcoordintpair = chunk.getPos(); boolean flag = this.isRaining(); int j = chunkcoordintpair.getMinBlockX(); -@@ -945,7 +980,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -973,7 +1088,7 @@ public class ServerLevel extends Level implements WorldGenLevel { ProfilerFiller gameprofilerfiller = this.getProfiler(); gameprofilerfiller.push("thunder"); @@ -14100,7 +13909,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e if (!this.paperConfig().environment.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper -@@ -1040,7 +1075,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1027,7 +1142,7 @@ public class ServerLevel extends Level implements WorldGenLevel { int yPos = (sectionIndex + minSection) << 4; for (int a = 0; a < randomTickSpeed; ++a) { int tickingBlocks = section.tickingList.size(); @@ -14109,7 +13918,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e if (index >= tickingBlocks) { continue; } -@@ -1054,7 +1089,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1041,7 +1156,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BlockPos blockposition2 = blockposition.set(j + randomX, randomY, k + randomZ); BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); @@ -14118,7 +13927,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // We drop the fluid tick since LAVA is ALREADY TICKED by the above method (See LiquidBlock). // TODO CHECK ON UPDATE (ping the Canadian) } -@@ -1108,7 +1143,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1141,7 +1256,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } public boolean isHandlingTick() { @@ -14127,7 +13936,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } public boolean canSleepThroughNights() { -@@ -1140,6 +1175,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1173,6 +1288,14 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void updateSleepingPlayerList() { @@ -14142,7 +13951,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e if (!this.players.isEmpty() && this.sleepStatus.update(this.players)) { this.announceSleepStatus(); } -@@ -1151,7 +1194,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1184,7 +1307,7 @@ public class ServerLevel extends Level implements WorldGenLevel { return this.server.getScoreboard(); } @@ -14151,7 +13960,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e boolean flag = this.isRaining(); if (this.dimensionType().hasSkyLight()) { -@@ -1237,23 +1280,24 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1270,23 +1393,24 @@ public class ServerLevel extends Level implements WorldGenLevel { this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel)); } // */ @@ -14185,7 +13994,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } } // CraftBukkit end -@@ -1317,7 +1361,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1350,7 +1474,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public void tickNonPassenger(Entity entity) { // Paper start - log detailed entity tick information @@ -14194,7 +14003,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e try { if (currentlyTickingEntity.get() == null) { currentlyTickingEntity.lazySet(entity); -@@ -1350,7 +1394,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1383,7 +1507,16 @@ public class ServerLevel extends Level implements WorldGenLevel { if (isActive) { // Paper - EAR 2 TimingHistory.activatedEntityTicks++; entity.tick(); @@ -14212,7 +14021,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } else { entity.inactiveTick(); } // Paper - EAR 2 this.getProfiler().pop(); } finally { timer.stopTiming(); } // Paper - timings -@@ -1373,7 +1426,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1406,7 +1539,7 @@ public class ServerLevel extends Level implements WorldGenLevel { private void tickPassenger(Entity vehicle, Entity passenger) { if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) { @@ -14221,7 +14030,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // Paper - EAR 2 final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(passenger); co.aikar.timings.Timing timer = isActive ? passenger.getType().passengerTickTimer.startTiming() : passenger.getType().passengerInactiveTickTimer.startTiming(); // Paper -@@ -1390,7 +1443,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1423,7 +1556,16 @@ public class ServerLevel extends Level implements WorldGenLevel { // Paper start - EAR 2 if (isActive) { passenger.rideTick(); @@ -14239,7 +14048,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } else { passenger.setDeltaMovement(Vec3.ZERO); passenger.inactiveTick(); -@@ -1478,7 +1540,15 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1511,7 +1653,15 @@ public class ServerLevel extends Level implements WorldGenLevel { // Paper - rewrite chunk system - entity saving moved into ChunkHolder } else if (close) { chunkproviderserver.close(false); } // Paper - rewrite chunk system @@ -14255,7 +14064,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // CraftBukkit start - moved from MinecraftServer.saveChunks ServerLevel worldserver1 = this; -@@ -1486,12 +1556,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1519,12 +1669,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save()); this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); // CraftBukkit end @@ -14269,7 +14078,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e this.getChunkSource().getDataStorage().save(); } -@@ -1546,6 +1611,19 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1579,6 +1724,19 @@ public class ServerLevel extends Level implements WorldGenLevel { return list; } @@ -14289,7 +14098,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e @Nullable public ServerPlayer getRandomPlayer() { List list = this.getPlayers(LivingEntity::isAlive); -@@ -1647,8 +1725,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1680,8 +1838,8 @@ public class ServerLevel extends Level implements WorldGenLevel { } else { if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added // Paper start - capture all item additions to the world @@ -14300,7 +14109,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e return true; } // Paper end -@@ -1792,7 +1870,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1825,7 +1983,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) { @@ -14309,7 +14118,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e String s = "recursive call to sendBlockUpdated"; Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated")); -@@ -1805,7 +1883,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1838,7 +1996,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { List list = new ObjectArrayList(); @@ -14318,7 +14127,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e while (iterator.hasNext()) { // CraftBukkit start - fix SPIGOT-6362 -@@ -1828,7 +1906,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1861,7 +2019,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } try { @@ -14327,7 +14136,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e iterator = list.iterator(); while (iterator.hasNext()) { -@@ -1837,7 +1915,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1870,7 +2028,7 @@ public class ServerLevel extends Level implements WorldGenLevel { navigationabstract1.recomputePath(); } } finally { @@ -14336,7 +14145,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } } -@@ -1846,23 +1924,23 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1879,23 +2037,23 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void updateNeighborsAt(BlockPos pos, Block sourceBlock) { @@ -14365,7 +14174,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } @Override -@@ -1893,7 +1971,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1926,7 +2084,7 @@ public class ServerLevel extends Level implements WorldGenLevel { explosion.clearToBlow(); } @@ -14374,7 +14183,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -1908,25 +1986,28 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1941,25 +2099,28 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void blockEvent(BlockPos pos, Block block, int type, int data) { @@ -14409,7 +14218,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } private boolean doBlockEvent(BlockEventData event) { -@@ -1937,12 +2018,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1970,12 +2131,12 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public LevelTicks getBlockTicks() { @@ -14424,7 +14233,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } @Nonnull -@@ -1966,7 +2047,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1999,7 +2160,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public int sendParticles(ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { // Paper start - Particle API Expansion @@ -14433,7 +14242,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } public int sendParticles(List receivers, ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) { // Paper end -@@ -2019,7 +2100,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2052,7 +2213,14 @@ public class ServerLevel extends Level implements WorldGenLevel { public Entity getEntityOrPart(int id) { Entity entity = (Entity) this.getEntities().get(id); @@ -14449,15 +14258,15 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } @Nullable -@@ -2179,6 +2267,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2219,6 +2387,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } public boolean setChunkForced(int x, int z, boolean forced) { + io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify force loaded chunks off of the global region"); // Folia - region threading - ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) this.getDataStorage().computeIfAbsent(ForcedChunksSavedData::load, ForcedChunksSavedData::new, "chunks"); + ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) this.getDataStorage().computeIfAbsent(ForcedChunksSavedData.factory(), "chunks"); ChunkPos chunkcoordintpair = new ChunkPos(x, z); long k = chunkcoordintpair.toLong(); -@@ -2187,7 +2276,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2227,7 +2396,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (forced) { flag1 = forcedchunk.getChunks().add(k); if (flag1) { @@ -14466,7 +14275,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } } else { flag1 = forcedchunk.getChunks().remove(k); -@@ -2215,13 +2304,18 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2255,13 +2424,18 @@ public class ServerLevel extends Level implements WorldGenLevel { BlockPos blockposition1 = pos.immutable(); optional.ifPresent((holder) -> { @@ -14488,7 +14297,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // Paper start if (optional.isEmpty() && this.getPoiManager().exists(blockposition1, poiType -> true)) { this.getPoiManager().remove(blockposition1); -@@ -2229,7 +2323,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2269,7 +2443,12 @@ public class ServerLevel extends Level implements WorldGenLevel { // Paper end this.getPoiManager().add(blockposition1, holder); DebugPackets.sendPoiAddedPacket(this, blockposition1); @@ -14502,7 +14311,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e }); } } -@@ -2276,7 +2375,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2316,7 +2495,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BufferedWriter bufferedwriter = Files.newBufferedWriter(path.resolve("stats.txt")); try { @@ -14511,7 +14320,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e NaturalSpawner.SpawnState spawnercreature_d = this.getChunkSource().getLastSpawnState(); if (spawnercreature_d != null) { -@@ -2290,7 +2389,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2330,7 +2509,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } bufferedwriter.write(String.format(Locale.ROOT, "entities: %s\n", this.entityLookup.getDebugInfo())); // Paper - rewrite chunk system @@ -14520,7 +14329,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e bufferedwriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); bufferedwriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); bufferedwriter.write("distance_manager: " + playerchunkmap.getDistanceManager().getDebugStatus() + "\n"); -@@ -2436,7 +2535,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2476,7 +2655,7 @@ public class ServerLevel extends Level implements WorldGenLevel { private void dumpBlockEntityTickers(Writer writer) throws IOException { CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("type").build(writer); @@ -14529,7 +14338,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e while (iterator.hasNext()) { TickingBlockEntity tickingblockentity = (TickingBlockEntity) iterator.next(); -@@ -2449,7 +2548,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2489,7 +2668,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @VisibleForTesting public void clearBlockEvents(BoundingBox box) { @@ -14538,7 +14347,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e return box.isInside(blockactiondata.pos()); }); } -@@ -2458,7 +2557,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2498,7 +2677,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public void blockUpdated(BlockPos pos, Block block) { if (!this.isDebug()) { // CraftBukkit start @@ -14547,7 +14356,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e return; } // CraftBukkit end -@@ -2501,9 +2600,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2541,9 +2720,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @VisibleForTesting public String getWatchdogStats() { @@ -14558,7 +14367,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } private static String getTypeCount(Iterable items, Function classifier) { -@@ -2536,6 +2633,12 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2576,6 +2753,12 @@ public class ServerLevel extends Level implements WorldGenLevel { public static void makeObsidianPlatform(ServerLevel worldserver, Entity entity) { // CraftBukkit end BlockPos blockposition = ServerLevel.END_SPAWN_POINT; @@ -14571,7 +14380,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e int i = blockposition.getX(); int j = blockposition.getY() - 2; int k = blockposition.getZ(); -@@ -2548,11 +2651,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2588,11 +2771,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BlockPos.betweenClosed(i - 2, j, k - 2, i + 2, j, k + 2).forEach((blockposition1) -> { blockList.setBlock(blockposition1, Blocks.OBSIDIAN.defaultBlockState(), 3); }); @@ -14584,7 +14393,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e blockList.updateList(); } // CraftBukkit end -@@ -2573,13 +2672,14 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2613,13 +2792,14 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void startTickingChunk(LevelChunk chunk) { @@ -14603,7 +14412,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } @Override -@@ -2601,7 +2701,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2641,7 +2821,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // Paper end - rewrite chunk system } @@ -14612,7 +14421,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // Paper start - optimize is ticking ready type functions io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = this.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded -@@ -2657,16 +2757,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2697,16 +2877,16 @@ public class ServerLevel extends Level implements WorldGenLevel { public void onCreated(Entity entity) {} public void onDestroyed(Entity entity) { @@ -14632,7 +14441,15 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e // Paper start - Reset pearls when they stop being ticked if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { pearl.cachedOwner = null; -@@ -2694,7 +2794,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2717,6 +2897,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + + public void onTrackingStart(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot ++ ServerLevel.this.getCurrentWorldData().addLoadedEntity(entity); // Folia - region threading + // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - moved down below valid=true + if (entity instanceof ServerPlayer) { + ServerPlayer entityplayer = (ServerPlayer) entity; +@@ -2734,7 +2915,7 @@ public class ServerLevel extends Level implements WorldGenLevel { Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); } @@ -14641,7 +14458,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } if (entity instanceof EnderDragon) { -@@ -2705,7 +2805,9 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2745,7 +2926,9 @@ public class ServerLevel extends Level implements WorldGenLevel { for (int j = 0; j < i; ++j) { EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; @@ -14651,7 +14468,13 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } } -@@ -2731,11 +2833,18 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2766,16 +2949,24 @@ public class ServerLevel extends Level implements WorldGenLevel { + + public void onTrackingEnd(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot ++ ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); + // Spigot start + if ( entity instanceof Player ) { com.google.common.collect.Streams.stream( ServerLevel.this.getServer().getAllLevels() ).map( ServerLevel::getDataStorage ).forEach( (worldData) -> { @@ -14671,7 +14494,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e map.carriedByPlayers.remove( (Player) entity ); for ( Iterator iter = (Iterator) map.carriedBy.iterator(); iter.hasNext(); ) { -@@ -2745,6 +2854,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2785,6 +2976,7 @@ public class ServerLevel extends Level implements WorldGenLevel { iter.remove(); } } @@ -14679,7 +14502,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } } } ); -@@ -2779,7 +2889,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2819,7 +3011,7 @@ public class ServerLevel extends Level implements WorldGenLevel { Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); } @@ -14688,7 +14511,7 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e } if (entity instanceof EnderDragon) { -@@ -2790,13 +2900,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2830,13 +3022,16 @@ public class ServerLevel extends Level implements WorldGenLevel { for (int j = 0; j < i; ++j) { EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; @@ -14706,10 +14529,10 @@ index 18aac3da3c88f33b1a71a5920a8daa27e9723913..bb07ad1bb895297356b88dfc4cd17e5e for (ServerPlayer player : ServerLevel.this.players) { player.getBukkitEntity().onEntityRemove(entity); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331aa63ef65 100644 +index d4aec99cac3f83d764e21946cc904c00e084704e..914910653d90c9519062a0f1ccc9bb2f1e3ec417 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -190,7 +190,7 @@ import org.bukkit.inventory.MainHand; +@@ -185,7 +185,7 @@ import org.bukkit.inventory.MainHand; public class ServerPlayer extends Player { private static final Logger LOGGER = LogUtils.getLogger(); @@ -14718,30 +14541,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; public ServerGamePacketListenerImpl connection; -@@ -251,12 +251,7 @@ public class ServerPlayer extends Player { - public boolean queueHealthUpdatePacket = false; - public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket; - // Paper end -- // Paper start - mob spawning rework -- public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length; -- public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper -- public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff -- public final com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet cachedSingleMobDistanceMap; -- // Paper end -+ // Folia - region threading - revert per player mob caps - - // CraftBukkit start - public String displayName; -@@ -417,7 +412,7 @@ public class ServerPlayer extends Player { - this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper - this.bukkitPickUpLoot = true; - this.maxHealthCache = this.getMaxHealth(); -- this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper -+ // Folia - region threading - revert per player mob caps - } - - // Yes, this doesn't match Vanilla, but it's the best we can do for now. -@@ -459,51 +454,152 @@ public class ServerPlayer extends Player { +@@ -462,51 +462,151 @@ public class ServerPlayer extends Player { } // CraftBukkit end @@ -14855,7 +14655,9 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 + ); + return true; + } -+ + +- while (!world.noCollision(this, this.getBoundingBox(), true) && this.getY() < (double) (world.getMaxBuildHeight() - 1)) { // Paper - make sure this loads chunks, we default to NOT loading now +- this.setPos(this.getX(), this.getY() + 1.0D, this.getZ()); + BlockPos selected = findSpawnAround(world, player, rough); + if (selected == null) { + return false; @@ -14871,9 +14673,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 + if (attemptCount[0] >= maxAttempts) { + BlockPos sharedSpawn = world.getSharedSpawnPos(); + BlockPos selected = world.getWorldBorder().clampToBounds((double)sharedSpawn.getX(), (double)sharedSpawn.getY(), (double)sharedSpawn.getZ()); - -- while (!world.noCollision(this, this.getBoundingBox(), true) && this.getY() < (double) (world.getMaxBuildHeight() - 1)) { // Paper - make sure this loads chunks, we default to NOT loading now -- this.setPos(this.getX(), this.getY() + 1.0D, this.getZ()); ++ + LOGGER.warn("Found no spawn in radius for player '" + player.getName() + "', ignoring radius"); + + // this call requires to return a location with loaded chunks, so we need to schedule a load here @@ -14888,7 +14688,6 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 } + } while (!trySpawnOrSchedule(world, player, random, attemptCount, maxAttempts, toComplete)); + } -+ + // Folia end - region threading + + public static void fudgeSpawnLocation(ServerLevel world, ServerPlayer player, ca.spottedleaf.concurrentutil.completable.Completable toComplete) { // Folia - region threading @@ -14924,7 +14723,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 return horizontalSpawnArea <= 16 ? horizontalSpawnArea - 1 : 17; } -@@ -1162,6 +1258,344 @@ public class ServerPlayer extends Player { +@@ -1165,6 +1265,337 @@ public class ServerPlayer extends Player { } } @@ -15084,7 +14883,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 + // select angle in direction of the difference applied to respawn pos? + Vec3 vec3d1 = Vec3.atBottomCenterOf(respawnPos).subtract(spawnPos).normalize(); + -+ locAngle = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); ++ locAngle = (float)Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); + } + ServerPlayer.this.setRespawnPosition( + respawnWorld.dimension(), respawnPos, respawnAngle, isRespawnForced, false, @@ -15169,15 +14968,8 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 + net.minecraft.world.level.storage.LevelData worlddata = destination.getLevelData(); + this.connection.send( + new ClientboundRespawnPacket( -+ destination.dimensionTypeId(), destination.dimension(), -+ BiomeManager.obfuscateSeed(destination.getSeed()), -+ this.gameMode.getGameModeForPlayer(), -+ this.gameMode.getPreviousGameModeForPlayer(), -+ destination.isDebug(), destination.isFlat(), -+ // if we do not want to respawn, we aren't dead -+ (teleportFlags & TELEPORT_FLAGS_PLAYER_RESPAWN) == 0L ? (byte)1 : (byte)0, -+ this.getLastDeathLocation(), -+ this.getPortalCooldown() ++ this.createCommonSpawnInfo(destination), ++ (teleportFlags & TELEPORT_FLAGS_PLAYER_RESPAWN) == 0L ? (byte)1 : (byte)0 + ) + ); + // don't bother with the chunk cache radius and simulation distance packets, they are handled @@ -15269,7 +15061,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 @Nullable @Override public Entity changeDimension(ServerLevel destination) { -@@ -1171,6 +1605,11 @@ public class ServerPlayer extends Player { +@@ -1174,6 +1605,11 @@ public class ServerPlayer extends Player { @Nullable public Entity changeDimension(ServerLevel worldserver, PlayerTeleportEvent.TeleportCause cause) { @@ -15281,7 +15073,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 // CraftBukkit end if (this.isSleeping()) return this; // CraftBukkit - SPIGOT-3154 // this.isChangingDimension = true; // CraftBukkit - Moved down and into PlayerList#changeDimension -@@ -2120,6 +2559,12 @@ public class ServerPlayer extends Player { +@@ -2126,6 +2562,12 @@ public class ServerPlayer extends Player { public void setCamera(@Nullable Entity entity) { Entity entity1 = this.getCamera(); @@ -15294,16 +15086,7 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 this.camera = (Entity) (entity == null ? this : entity); if (entity1 != this.camera) { // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity Event -@@ -2313,7 +2758,7 @@ public class ServerPlayer extends Player { - } - - public void untrackChunk(ChunkPos chunkPos) { -- if (this.isAlive()) { -+ if (true || this.isAlive()) { // Folia - region threading - always untrack chunk now that the player is retained in the world after death - this.connection.send(new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z)); - // Paper start - if(io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0){ -@@ -2632,7 +3077,7 @@ public class ServerPlayer extends Player { +@@ -2624,7 +3066,7 @@ public class ServerPlayer extends Player { this.experienceLevel = this.newLevel; this.totalExperience = this.newTotalExp; this.experienceProgress = 0; @@ -15313,15 +15096,10 @@ index b382da838acc04a1c5d89064b4fa43bcdd38ae71..587934b8e96a3d8b8a57cda8730eb331 this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DEATH); this.effectsDirty = true; diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 618ab9a2903f6d4139acd4aaa2e6db0a26e88ba9..82e9307e4c95edc30c9dd78cd3fefa8725140361 100644 +index b2c2bd5ec0afd479973f7237a5c610f21231c505..fff64e3b5cd72a64d95a1439b42472f8a646d18a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -124,11 +124,11 @@ public class ServerPlayerGameMode { - } - - public void tick() { -- this.gameTicks = MinecraftServer.currentTick; // CraftBukkit; -+ ++this.gameTicks; // CraftBukkit; // Folia - region threading +@@ -128,7 +128,7 @@ public class ServerPlayerGameMode { BlockState iblockdata; if (this.hasDelayedDestroy) { @@ -15360,7 +15138,7 @@ index 618ab9a2903f6d4139acd4aaa2e6db0a26e88ba9..82e9307e4c95edc30c9dd78cd3fefa87 org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - use stored ref } diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 76bd323f25d7c2f4e12dd13baa53995fa4f8b27a..6a4265fb1fd4bb2c032c0da6c71532d56409428f 100644 +index f382d138959b34bfc3a114bc9d96e056cccbfc89..100293099156978ff701bc6c9d8df94ba8282021 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -97,10 +97,15 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl @@ -15487,26 +15265,157 @@ index 877498729c66de9aa6a27c9148f7494d7895615c..d8af2d59fb1f112f2f1a9fdbb3517fc7 public WorldGenRegion(ServerLevel world, List chunks, ChunkStatus status, int placementRadius) { this.generatingStatus = status; this.writeRadiusCutoff = placementRadius; +diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index 231150bac0ae61e9722c2cdfd70d6f7d254681e4..7c2e1bd6290e17b2d48a387b2a60350b59eb2e87 100644 +--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -86,6 +86,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + ServerCommonPacketListenerImpl.LOGGER.info("Stopping singleplayer server as player logged out"); + this.server.halt(false); + } ++ this.player.getBukkitEntity().taskScheduler.retire(); // Folia - region threading + + } + +@@ -99,9 +100,9 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + this.keepAlivePending = false; + } else if (!this.isSingleplayerOwner()) { + // Paper start - This needs to be handled on the main thread for plugins +- server.submit(() -> { ++ // Folia - region threading - do not schedule to main anymore, there is no main + this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause +- }); ++ // Folia - region threading - do not schedule to main anymore, there is no main + // Paper endg + } + +@@ -287,24 +288,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + if (this.processedDisconnect) { + return; + } +- if (!this.cserver.isPrimaryThread()) { +- Waitable waitable = new Waitable() { +- @Override +- protected Object evaluate() { +- ServerCommonPacketListenerImpl.this.disconnect(reason, cause); // Paper - adventure +- return null; +- } +- }; +- +- this.server.processQueue.add(waitable); +- +- try { +- waitable.get(); +- } catch (InterruptedException e) { +- Thread.currentThread().interrupt(); +- } catch (ExecutionException e) { +- throw new RuntimeException(e); +- } ++ if (!io.papermc.paper.util.TickThread.isTickThreadFor(this.player)) { // Folia - region threading ++ this.connection.disconnectSafely(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason), cause); // Folia - region threading - it HAS to be delayed/async to avoid deadlock if we try to wait for another region + return; + } + +@@ -335,7 +320,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + + Objects.requireNonNull(this.connection); + // CraftBukkit - Don't wait +- minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper ++ // Folia - region threading + } + + protected boolean isSingleplayerOwner() { +diff --git a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java +index 8dbcc1b3a70b6bbea3bd2d15b6d66cc4f9cd53f8..d57130a8e1d28ce2458d11197911d12b9ca801ea 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java +@@ -43,6 +43,7 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis + @Nullable + private ConfigurationTask currentTask; + private ClientInformation clientInformation; ++ public boolean switchToMain = false; // Folia - region threading - rewrite login process + + public ServerConfigurationPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit + super(minecraftserver, networkmanager, commonlistenercookie, player); // CraftBukkit +@@ -127,7 +128,57 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis + + ServerPlayer entityplayer = playerlist.getPlayerForLogin(this.gameProfile, this.clientInformation, this.player); // CraftBukkit + +- playerlist.placeNewPlayer(this.connection, entityplayer, this.createCookie(this.clientInformation)); ++ // Folia start - region threading - rewrite login process ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot handle player login off global tick thread"); ++ CommonListenerCookie clientData = this.createCookie(this.clientInformation); ++ org.apache.commons.lang3.mutable.MutableObject data = new org.apache.commons.lang3.mutable.MutableObject<>(); ++ org.apache.commons.lang3.mutable.MutableObject lastKnownName = new org.apache.commons.lang3.mutable.MutableObject<>(); ++ ca.spottedleaf.concurrentutil.completable.Completable toComplete = new ca.spottedleaf.concurrentutil.completable.Completable<>(); ++ // note: need to call addWaiter before completion to ensure the callback is invoked synchronously ++ // the loadSpawnForNewPlayer function always completes the completable once the chunks were loaded, ++ // on the load callback for those chunks (so on the same region) ++ // this guarantees the chunk cannot unload under our feet ++ toComplete.addWaiter((org.bukkit.Location loc, Throwable t) -> { ++ int chunkX = net.minecraft.util.Mth.floor(loc.getX()) >> 4; ++ int chunkZ = net.minecraft.util.Mth.floor(loc.getZ()) >> 4; ++ ++ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)loc.getWorld()).getHandle(); ++ // we just need to hold the chunks at loaded until the next tick ++ // so we do not need to care about unique IDs for the ticket ++ world.getChunkSource().addTicketAtLevel( ++ net.minecraft.server.level.TicketType.LOGIN, ++ new net.minecraft.world.level.ChunkPos(chunkX, chunkZ), ++ io.papermc.paper.chunk.system.scheduling.ChunkHolderManager.FULL_LOADED_TICKET_LEVEL, ++ net.minecraft.util.Unit.INSTANCE ++ ); ++ ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( ++ world, chunkX, chunkZ, ++ () -> { ++ // once switchToMain is set, the current ticking region now owns the connection and is responsible ++ // for cleaning it up ++ playerlist.placeNewPlayer( ++ ServerConfigurationPacketListenerImpl.this.connection, ++ entityplayer, ++ clientData, ++ data.getValue(), ++ lastKnownName.getValue(), ++ loc ++ ); ++ }, ++ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER ++ ); ++ }); ++ this.switchToMain = true; ++ try { ++ // now the connection responsibility is transferred on the region ++ playerlist.loadSpawnForNewPlayer(this.connection, entityplayer, clientData, data, lastKnownName, toComplete); ++ } catch (final Throwable throwable) { ++ // assume toComplete will not be invoked ++ // ensure global tick thread owns the connection again, to properly disconnect it ++ this.switchToMain = false; ++ } ++ // Folia end - region threading - rewrite login process + this.connection.resumeInboundAfterProtocolChange(); + } catch (Exception exception) { + ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 44d99e89226adb6234b9405f25ac9dab9bd84297..072634e26d32ca0b3438a5d3a03be3670d0f846e 100644 +index 79326308f6126f84a3cbb3d5a33302de048d8a50..81090d1b5d67506268a41c6387a1d45302e88a5c 100644 --- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -154,10 +154,13 @@ public class ServerConnectionListener { +@@ -158,10 +158,13 @@ public class ServerConnectionListener { + }); + } // Paper end - - //ServerConnectionListener.this.connections.add(object); - pending.add(object); // Paper + // Folia - connection fixes - move down - channelpipeline.addLast("packet_handler", (ChannelHandler) object); - ((Connection) object).setListener(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); + ((Connection) object).configurePacketHandler(channelpipeline); + ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper + // Folia start - regionised threading -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addConnection((Connection)object); ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addConnection(object); + // Folia end - regionised threading } - }).group((EventLoopGroup) lazyinitvar.get()).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper + }).group(eventloopgroup).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper } -@@ -218,7 +221,7 @@ public class ServerConnectionListener { +@@ -224,7 +227,7 @@ public class ServerConnectionListener { // Spigot Start this.addPending(); // Paper // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order @@ -15516,13 +15425,22 @@ index 44d99e89226adb6234b9405f25ac9dab9bd84297..072634e26d32ca0b3438a5d3a03be367 Collections.shuffle( this.connections ); } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4fe27d53bc 100644 +index 8bd243a8d5a4be54f907af2b02e96ea833cee62f..10ce902a1ce857db5376c8318ba0e67b53883873 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -327,10 +327,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -289,7 +289,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private final LastSeenMessagesValidator lastSeenMessages; + private final MessageSignatureCache messageSignatureCache; + private final FutureChain chatMessageChain; +- private boolean waitingForSwitchToConfig; ++ public volatile boolean waitingForSwitchToConfig; // Folia - rewrite login process - fix bad ordering of this field write + public + private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - private final org.bukkit.craftbukkit.CraftServer cserver; - public boolean processedDisconnect; + public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) { +@@ -307,10 +307,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + + // CraftBukkit start - add fields - private int lastTick = MinecraftServer.currentTick; + private long lastTick = Util.getMillis() / 50L; // Folia - region threading private int allowedPlayerTicks = 1; @@ -15533,8 +15451,8 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f private int dropCount = 0; // Get position of last block hit for BlockDamageLevel.STOPPED -@@ -347,8 +347,40 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - } +@@ -323,8 +323,21 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + private boolean hasMoved; // Spigot // CraftBukkit end + // Folia start - region threading @@ -15542,31 +15460,12 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f + private static final java.util.concurrent.atomic.AtomicLong DISCONNECT_TICKET_ID_GENERATOR = new java.util.concurrent.atomic.AtomicLong(); + public static final net.minecraft.server.level.TicketType DISCONNECT_TICKET = net.minecraft.server.level.TicketType.create("disconnect_ticket", Long::compareTo); + public final Long disconnectTicketId = Long.valueOf(DISCONNECT_TICKET_ID_GENERATOR.getAndIncrement()); -+ -+ private void checkKeepAlive() { -+ long currentTime = Util.getMillis(); -+ long elapsedTime = currentTime - this.keepAliveTime; -+ -+ if (this.keepAlivePending) { -+ if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected -+ ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info -+ this.disconnect(Component.translatable("disconnect.timeout", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause -+ } -+ } else { -+ if (elapsedTime >= 15000L) { // 15 seconds -+ this.keepAlivePending = true; -+ this.keepAliveTime = currentTime; -+ this.keepAliveChallenge = currentTime; -+ this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge)); -+ } -+ } -+ } + // Folia end - region threading + @Override public void tick() { + // Folia start - region threading -+ this.checkKeepAlive(); ++ this.keepConnectionAlive(); + if (this.player.wonGame) { + return; + } @@ -15574,31 +15473,16 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f if (this.ackBlockChangesUpTo > -1) { this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); this.ackBlockChangesUpTo = -1; -@@ -400,22 +432,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - this.server.getProfiler().push("keepAlive"); - // Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings - // This should effectively place the keepalive handling back to "as it was" before 1.12.2 -- long currentTime = Util.getMillis(); -- long elapsedTime = currentTime - this.keepAliveTime; -- -- if (this.keepAlivePending) { -- if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected -- ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info -- this.disconnect(Component.translatable("disconnect.timeout", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause -- } -- } else { -- if (elapsedTime >= 15000L) { // 15 seconds -- this.keepAlivePending = true; -- this.keepAliveTime = currentTime; -- this.keepAliveChallenge = currentTime; -- this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge)); -- } -- } -+ // Folia - region threading - move to own method above - // Paper end +@@ -373,7 +386,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.aboveGroundVehicleTickCount = 0; + } - this.server.getProfiler().pop(); -@@ -455,6 +472,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +- this.keepConnectionAlive(); ++ // Folia - region threading - moved to beginning of method + // CraftBukkit start + for (int spam; (spam = this.chatSpamTickCount.get()) > 0 && !this.chatSpamTickCount.compareAndSet(spam, spam - 1); ) ; + if (tabSpamLimiter.get() > 0) tabSpamLimiter.getAndDecrement(); // Paper - split to seperate variable +@@ -410,6 +423,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.lastGoodX = this.player.getX(); this.lastGoodY = this.player.getY(); this.lastGoodZ = this.player.getZ(); @@ -15618,42 +15502,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } @Override -@@ -491,24 +521,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - if (this.processedDisconnect) { - return; - } -- if (!this.cserver.isPrimaryThread()) { -- Waitable waitable = new Waitable() { -- @Override -- protected Object evaluate() { -- ServerGamePacketListenerImpl.this.disconnect(reason, cause); // Paper - adventure, kick event cause -- return null; -- } -- }; -- -- this.server.processQueue.add(waitable); -- -- try { -- waitable.get(); -- } catch (InterruptedException e) { -- Thread.currentThread().interrupt(); -- } catch (ExecutionException e) { -- throw new RuntimeException(e); -- } -+ if (!io.papermc.paper.util.TickThread.isTickThreadFor(this.player)) { // Folia - region threading -+ this.connection.disconnectSafely(PaperAdventure.asVanilla(reason), cause); // Folia - region threading - it HAS to be delayed/async to avoid deadlock if we try to wait for another region - return; - } - -@@ -539,7 +553,6 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - - Objects.requireNonNull(this.connection); - // CraftBukkit - Don't wait -- minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper - } - - private CompletableFuture filterTextPacket(T text, BiFunction> filterer) { -@@ -621,9 +634,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -506,9 +532,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // Paper end - fix large move vectors killing the server // CraftBukkit start - handle custom speeds and skipped ticks @@ -15666,7 +15515,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f ++this.receivedMovePacketCount; int i = this.receivedMovePacketCount - this.knownMovePacketCount; -@@ -698,7 +712,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -583,7 +610,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl Location curPos = this.getCraftPlayer().getLocation(); // Spigot entity.absMoveTo(d3, d4, d5, f, f1); @@ -15675,13 +15524,13 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f // Paper start - optimise out extra getCubes boolean teleportBack = flag2; // violating this is always a fail -@@ -711,11 +725,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -596,11 +623,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } if (teleportBack) { // Paper end - optimise out extra getCubes entity.absMoveTo(d0, d1, d2, f, f1); - this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit + //this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit // Folia - not needed, the player is no longer updated - this.connection.send(new ClientboundMoveVehiclePacket(entity)); + this.send(new ClientboundMoveVehiclePacket(entity)); return; } @@ -15696,7 +15545,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f // CraftBukkit start - fire PlayerMoveEvent Player player = this.getCraftPlayer(); // Spigot Start -@@ -761,7 +783,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -646,7 +681,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { @@ -15705,7 +15554,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } -@@ -769,7 +791,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -654,7 +689,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. // We only do this if the Event was not cancelled. if (!oldTo.equals(event.getTo()) && !event.isCancelled()) { @@ -15714,7 +15563,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } -@@ -885,13 +907,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -770,13 +805,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - run this async // CraftBukkit start if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable @@ -15725,12 +15574,12 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f // Paper start String str = packet.getCommand(); int index = -1; if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) { -- server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper -+ this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper // Folia - region threading +- server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper ++ this.disconnect(Component.translatable("disconnect.spam", new Object[0])); // Paper // Folia - region threading return; } // Paper end -@@ -916,7 +938,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -801,7 +836,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (!event.isHandled()) { if (!event.isCancelled()) { @@ -15739,7 +15588,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { -@@ -932,7 +954,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -817,7 +852,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); // Paper end - Brigadier API }); @@ -15748,7 +15597,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } } else if (!completions.isEmpty()) { final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(command, stringreader.getTotalLength()); -@@ -1244,7 +1266,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1129,7 +1164,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; if (byteLength > 256 * 4) { ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send a book with with a page too large!"); @@ -15757,7 +15606,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } byteTotal += byteLength; -@@ -1267,17 +1289,17 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1152,17 +1187,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (byteTotal > byteAllowed) { ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size()); @@ -15779,7 +15628,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f // CraftBukkit end int i = packet.getSlot(); -@@ -1297,7 +1319,19 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1182,7 +1217,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.updateBookContents(list1, i); }; @@ -15800,7 +15649,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } } -@@ -1463,9 +1497,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1348,9 +1395,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl int i = this.receivedMovePacketCount - this.knownMovePacketCount; // CraftBukkit start - handle custom speeds and skipped ticks @@ -15813,7 +15662,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f if (i > Math.max(this.allowedPlayerTicks, 5)) { ServerGamePacketListenerImpl.LOGGER.debug("{} is sending move packets too frequently ({} packets since last tick)", this.player.getName().getString(), i); -@@ -1651,7 +1686,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1536,7 +1584,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { @@ -15822,7 +15671,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } -@@ -1659,7 +1694,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1544,7 +1592,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. // We only do this if the Event was not cancelled. if (!oldTo.equals(event.getTo()) && !event.isCancelled()) { @@ -15831,7 +15680,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } -@@ -1885,9 +1920,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1777,9 +1825,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (!this.player.isSpectator()) { // limit how quickly items can be dropped // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick. @@ -15843,7 +15692,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } else { // Else we increment the drop count and check the amount. this.dropCount++; -@@ -1915,7 +1950,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1807,7 +1855,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl case ABORT_DESTROY_BLOCK: case STOP_DESTROY_BLOCK: // Paper start - Don't allow digging in unloaded chunks @@ -15852,7 +15701,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f this.player.connection.ackBlockChangesUpTo(packet.getSequence()); return; } -@@ -1999,7 +2034,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -1891,7 +1939,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl BlockPos blockposition = movingobjectpositionblock.getBlockPos(); Vec3 vec3d1 = Vec3.atCenterOf(blockposition); @@ -15861,7 +15710,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f Vec3 vec3d2 = vec3d.subtract(vec3d1); double d0 = 1.0000001D; -@@ -2113,7 +2148,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2005,7 +2053,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl Entity entity = packet.getEntity(worldserver); if (entity != null) { @@ -15870,16 +15719,34 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } } -@@ -2176,6 +2211,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2042,7 +2090,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + // CraftBukkit end + ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), reason.getString()); +- this.removePlayerFromWorld(quitMessage); // Paper ++ if (!this.waitingForSwitchToConfig) this.removePlayerFromWorld(quitMessage); // Paper // Folia - region threading + super.onDisconnect(reason, quitMessage); // Paper + } + +@@ -2051,6 +2099,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + this.removePlayerFromWorld(null); + } + ++ public boolean hackSwitchingConfig; // Folia - rewrite login process ++ + private void removePlayerFromWorld(@Nullable net.kyori.adventure.text.Component quitMessage) { + // Paper end + this.chatMessageChain.close(); +@@ -2063,6 +2113,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.player.disconnect(); // Paper start - Adventure quitMessage = quitMessage == null ? this.server.getPlayerList().remove(this.player) : this.server.getPlayerList().remove(this.player, quitMessage); // Paper - pass in quitMessage to fix kick message not being used -+ this.disconnectPos = this.player.chunkPosition(); // Folia - region threading - note: only set after removing, since it can tick the player -+ this.player.serverLevel().chunkSource.addTicketAtLevel(DISCONNECT_TICKET, this.disconnectPos, io.papermc.paper.chunk.system.scheduling.ChunkHolderManager.MAX_TICKET_LEVEL, this.disconnectTicketId); // Folia - region threading - force chunk to be loaded so that the region is not lost ++ if (!this.hackSwitchingConfig) this.disconnectPos = this.player.chunkPosition(); // Folia - region threading - note: only set after removing, since it can tick the player ++ if (!this.hackSwitchingConfig) this.player.serverLevel().chunkSource.addTicketAtLevel(DISCONNECT_TICKET, this.disconnectPos, io.papermc.paper.chunk.system.scheduling.ChunkHolderManager.MAX_TICKET_LEVEL, this.disconnectTicketId); // Folia - region threading - force chunk to be loaded so that the region is not lost if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) { this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(quitMessage), false); // Paper end -@@ -2261,9 +2298,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2115,9 +2167,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } // CraftBukkit end if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.message())) { @@ -15891,7 +15758,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } else { Optional optional = this.tryHandleChat(packet.message(), packet.timeStamp(), packet.lastSeenMessages()); -@@ -2297,23 +2334,22 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2150,23 +2202,22 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl @Override public void handleChatCommand(ServerboundChatCommandPacket packet) { if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.command())) { @@ -15919,19 +15786,19 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } } -@@ -2387,9 +2423,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2240,9 +2291,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl private Optional tryHandleChat(String message, Instant timestamp, LastSeenMessages.Update acknowledgment) { if (!this.updateChatOrder(timestamp)) { ServerGamePacketListenerImpl.LOGGER.warn("{} sent out-of-order chat: '{}': {} > {}", this.player.getName().getString(), message, this.lastChatTimeStamp.get().getEpochSecond(), timestamp.getEpochSecond()); // Paper - this.server.scheduleOnMain(() -> { // Paper - push to main + // Folia - region threading - this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event ca + this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes - }); // Paper - push to main + // Folia - region threading return Optional.empty(); } else { Optional optional = this.unpackAndApplyLastSeen(acknowledgment); -@@ -2464,7 +2500,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2317,7 +2368,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl String originalFormat = event.getFormat(), originalMessage = event.getMessage(); this.cserver.getPluginManager().callEvent(event); @@ -15940,23 +15807,42 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f // Evil plugins still listening to deprecated event final PlayerChatEvent queueEvent = new PlayerChatEvent(player, event.getMessage(), event.getFormat(), event.getRecipients()); queueEvent.setCancelled(event.isCancelled()); -@@ -2536,6 +2572,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - public void handleCommand(String s) { // Paper - private -> public - // Paper Start - if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) { -+ if (true) throw new UnsupportedOperationException(); // Folia - region threading - LOGGER.error("Command Dispatched Async: " + s); - LOGGER.error("Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable()); - Waitable wait = new Waitable<>() { -@@ -2596,6 +2633,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2428,6 +2479,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl if (s.isEmpty()) { ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send an empty message"); - } else if (this.getCraftPlayer().isConversing()) { + } else if (getCraftPlayer().isConversing()) { + if (true) throw new UnsupportedOperationException(); // Folia - region threading final String conversationInput = s; this.server.processQueue.add(new Runnable() { @Override -@@ -2847,7 +2885,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2664,8 +2716,25 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Spigot End + + public void switchToConfig() { +- this.waitingForSwitchToConfig = true; ++ // Folia start - rewrite login process ++ io.papermc.paper.util.TickThread.ensureTickThread(this.player, "Cannot switch config off-main"); ++ if (io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread()) { ++ throw new IllegalStateException("Cannot switch config while on global tick thread"); ++ } ++ // Folia end - rewrite login process ++ // Folia start - rewrite login process - fix bad ordering of this field write - move after removed from world ++ // the field write ordering is bad as it allows the client to send the response packet before the player is ++ // removed from the world ++ // Folia end - rewrite login process - fix bad ordering of this field write - move after removed from world ++ try { // Folia - rewrite login process - move connection ownership to global region ++ this.hackSwitchingConfig = true; // Folia - rewrite login process - avoid adding logout ticket here and retiring scheduler + this.removePlayerFromWorld(); ++ } finally { // Folia start - rewrite login process - move connection ownership to global region ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.player.serverLevel().getCurrentWorldData(); ++ worldData.connections.remove(this.connection); ++ // once waitingForSwitchToConfig is set, the global tick thread will own the connection ++ } // Folia end - rewrite login process - move connection ownership to global region ++ this.waitingForSwitchToConfig = true; // Folia - rewrite login process - fix bad ordering of this field write - moved down + this.send(new ClientboundStartConfigurationPacket()); + } + +@@ -2690,7 +2759,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.player.resetLastActionTime(); this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); @@ -15965,7 +15851,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f if (!worldserver.getWorldBorder().isWithinBounds(entity.blockPosition())) { return; } -@@ -2988,6 +3026,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2831,6 +2900,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl switch (packetplayinclientcommand_enumclientcommand) { case PERFORM_RESPAWN: if (this.player.wonGame) { @@ -15978,7 +15864,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f this.player.wonGame = false; this.player = this.server.getPlayerList().respawn(this.player, this.server.getLevel(this.player.getRespawnDimension()), true, null, true, RespawnReason.END_PORTAL, org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag.END_PORTAL); // Paper - add isEndCreditsRespawn argument CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); -@@ -2996,6 +3040,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2839,6 +2914,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl return; } @@ -15997,7 +15883,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f this.player = this.server.getPlayerList().respawn(this.player, false, RespawnReason.DEATH); if (this.server.isHardcore()) { this.player.setGameMode(GameType.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper -@@ -3349,7 +3405,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3192,7 +3279,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // Paper start if (!org.bukkit.Bukkit.isPrimaryThread()) { if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { @@ -16006,7 +15892,7 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f return; } } -@@ -3518,7 +3574,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3361,7 +3448,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.filterTextPacket(list).thenAcceptAsync((list1) -> { this.updateSignText(packet, list1); @@ -16026,145 +15912,37 @@ index 3c0651fa5a5db880202c9a3805a6455269c5f16d..0114f9e669d3d54a61e909ff2a706d4f } private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { -@@ -3551,9 +3618,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - this.keepAlivePending = false; - } else if (!this.isSingleplayerOwner()) { - // Paper start - This needs to be handled on the main thread for plugins -- server.submit(() -> { -+ // Folia - region threading - do not schedule to main anymore, there is no main - this.disconnect(Component.translatable("disconnect.timeout"), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause -- }); -+ // Folia - region threading - do not schedule to main anymore, there is no main - // Paper end - } - diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 2ff578e4a953ffcf5176815ba8e3f06f73499989..2e96377d628b3a07fb565020074d665f594f32e8 100644 +index ff2dd53e9e943aa929188fd9d4c35498b78c497a..57649d7fd11bef6395e04c075980e4c34eeffaa8 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -53,7 +53,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - private final byte[] challenge; - final MinecraftServer server; - public final Connection connection; -- public ServerLoginPacketListenerImpl.State state; -+ public volatile ServerLoginPacketListenerImpl.State state; // Folia - region threading - private int tick; - public @Nullable - GameProfile gameProfile; -@@ -80,20 +80,14 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -82,9 +82,13 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, } // Paper end - if (this.state == ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT) { -- // Paper start - prevent logins to be processed even though disconnect was called -- if (connection.isConnected()) { + if (this.state == ServerLoginPacketListenerImpl.State.VERIFYING) { +- if (this.connection.isConnected()) { // Paper - prevent logins to be processed even though disconnect was called + // Folia start - region threading - rewrite login process -+ String name = this.gameProfile.getName(); -+ UUID uniqueId = UUIDUtil.getOrCreatePlayerUUID(this.gameProfile); ++ String name = this.authenticatedProfile.getName(); ++ UUID uniqueId = this.authenticatedProfile.getId(); + if (this.server.getPlayerList().pushPendingJoin(name, uniqueId, this.connection)) { - this.handleAcceptedLogin(); - } -- // Paper end -- } else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) { -- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId()); -- -- if (entityplayer == null) { -- this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT; -- this.placeNewPlayer(this.delayedAcceptPlayer); -- this.delayedAcceptPlayer = null; -- } -- } + // Folia end - region threading - rewrite login process -+ } // Folia - region threading - remove delayed accept + this.verifyLoginAndFinishConnectionSetup((GameProfile) Objects.requireNonNull(this.authenticatedProfile)); +- } // Paper ++ } // Folia - region threading - rewrite login process + } - if (this.tick++ == 600) { - this.disconnect(Component.translatable("multiplayer.disconnect.slow_login")); -@@ -163,7 +157,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - // this.disconnect(ichatbasecomponent); - // CraftBukkit end - } else { -- this.state = ServerLoginPacketListenerImpl.State.ACCEPTED; -+ this.state = ServerLoginPacketListenerImpl.State.HANDING_OFF; // Folia - region threading - rewrite login process - if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) { - this.connection.send(new ClientboundLoginCompressionPacket(this.server.getCompressionThreshold()), PacketSendListener.thenRun(() -> { - this.connection.setupCompression(this.server.getCompressionThreshold(), true); -@@ -171,17 +165,55 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + if (this.state == ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT && !this.isPlayerAlreadyInWorld((GameProfile) Objects.requireNonNull(this.authenticatedProfile))) { +@@ -227,7 +231,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + })); } - this.connection.send(new ClientboundGameProfilePacket(this.gameProfile)); -- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId()); -+ // Folia - region threading - rewrite login process +- boolean flag = playerlist.disconnectAllPlayersWithProfile(profile, this.player); // CraftBukkit - add player reference ++ boolean flag = false && playerlist.disconnectAllPlayersWithProfile(profile, this.player); // CraftBukkit - add player reference // Folia - rewrite login process - always false here - try { -- ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference -- -- if (entityplayer != null) { -- this.state = ServerLoginPacketListenerImpl.State.DELAY_ACCEPT; -- this.delayedAcceptPlayer = entityplayer1; -- } else { -- this.placeNewPlayer(entityplayer1); -- } -+ // Folia start - region threading - rewrite login process -+ org.apache.commons.lang3.mutable.MutableObject data = new org.apache.commons.lang3.mutable.MutableObject<>(); -+ org.apache.commons.lang3.mutable.MutableObject lastKnownName = new org.apache.commons.lang3.mutable.MutableObject<>(); -+ ca.spottedleaf.concurrentutil.completable.Completable toComplete = new ca.spottedleaf.concurrentutil.completable.Completable<>(); -+ // note: need to call addWaiter before completion to ensure the callback is invoked synchronously -+ // the loadSpawnForNewPlayer function always completes the completable once the chunks were loaded, -+ // on the load callback for those chunks (so on the same region) -+ // this guarantees the chunk cannot unload under our feet -+ toComplete.addWaiter((org.bukkit.Location loc, Throwable t) -> { -+ int chunkX = net.minecraft.util.Mth.floor(loc.getX()) >> 4; -+ int chunkZ = net.minecraft.util.Mth.floor(loc.getZ()) >> 4; -+ -+ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)loc.getWorld()).getHandle(); -+ // we just need to hold the chunks at loaded until the next tick -+ // so we do not need to care about unique IDs for the ticket -+ world.getChunkSource().addTicketAtLevel( -+ net.minecraft.server.level.TicketType.LOGIN, -+ new net.minecraft.world.level.ChunkPos(chunkX, chunkZ), -+ io.papermc.paper.chunk.system.scheduling.ChunkHolderManager.FULL_LOADED_TICKET_LEVEL, -+ net.minecraft.util.Unit.INSTANCE -+ ); -+ -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ world, chunkX, chunkZ, -+ () -> { -+ // now at this point the connection is held by the region, so we have to check isConnected() -+ // this would have been handled in connection ticking, but we are in a state between -+ // being owned by the global tick thread and the region so we have to do it -+ if (t != null || !ServerLoginPacketListenerImpl.this.connection.isConnected()) { -+ ServerLoginPacketListenerImpl.this.connection.handleDisconnection(); -+ return; -+ } -+ ServerLoginPacketListenerImpl.this.state = State.ACCEPTED; -+ ServerLoginPacketListenerImpl.this.server.getPlayerList().placeNewPlayer( -+ ServerLoginPacketListenerImpl.this.connection, -+ s, -+ data.getValue(), -+ lastKnownName.getValue(), -+ loc -+ ); -+ }, -+ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER -+ ); -+ }); -+ this.server.getPlayerList().loadSpawnForNewPlayer(this.connection, s, data, lastKnownName, toComplete); -+ // Folia end - region threading - rewrite login process - } catch (Exception exception) { - ServerLoginPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); - MutableComponent ichatmutablecomponent = Component.translatable("multiplayer.disconnect.invalid_player_data"); -@@ -198,9 +230,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - - } - -- private void placeNewPlayer(ServerPlayer player) { -- this.server.getPlayerList().placeNewPlayer(this.connection, player); -- } -+ // Folia end - region threading - rewrite login process - - @Override - public void onDisconnect(Component reason) { -@@ -397,7 +427,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - uniqueId = gameProfile.getId(); + if (flag) { + this.state = ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT; +@@ -353,7 +357,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + uniqueId = gameprofile.getId(); // Paper end - if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) { @@ -16172,17 +15950,8 @@ index 2ff578e4a953ffcf5176815ba8e3f06f73499989..2e96377d628b3a07fb565020074d665f final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId); if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) { event.disallow(asyncEvent.getResult(), asyncEvent.kickMessage()); // Paper - Adventure -@@ -480,7 +510,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - - public static enum State { - -- HELLO, KEY, AUTHENTICATING, NEGOTIATING, READY_TO_ACCEPT, DELAY_ACCEPT, ACCEPTED; -+ HELLO, KEY, AUTHENTICATING, NEGOTIATING, READY_TO_ACCEPT, DELAY_ACCEPT, HANDING_OFF, ACCEPTED; // Folia - region threading - - private State() {} - } diff --git a/src/main/java/net/minecraft/server/players/BanListEntry.java b/src/main/java/net/minecraft/server/players/BanListEntry.java -index 8f19876c20ce9cce574ebbec386a26ab5c807e18..4627c7bd326ca42c9476ec17867dba2ad4191b86 100644 +index 8b1da1fb5ca27432a39aff6dbc452b793268dab5..e83f3676d5a194fa8d3d1567edcb4b6f7847a4c1 100644 --- a/src/main/java/net/minecraft/server/players/BanListEntry.java +++ b/src/main/java/net/minecraft/server/players/BanListEntry.java @@ -10,7 +10,7 @@ import net.minecraft.network.chat.Component; @@ -16234,10 +16003,10 @@ index 8f19876c20ce9cce574ebbec386a26ab5c807e18..4627c7bd326ca42c9476ec17867dba2a // Guess we don't have a date } diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java -index 7edd4b88eb0476f0630630bc4681e859bd145b2b..f3586a5c5b5d4cae817aa7c15fc0c2fc4cd6dc09 100644 +index ce43cb0152ba07c6c21e08142d65813d47c3b63b..8bdb1d10648965e2011b4a22a1dfc575d3bbe4e0 100644 --- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java +++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java -@@ -517,7 +517,7 @@ public class OldUsersConverter { +@@ -512,7 +512,7 @@ public class OldUsersConverter { Date date1; try { @@ -16247,11 +16016,11 @@ index 7edd4b88eb0476f0630630bc4681e859bd145b2b..f3586a5c5b5d4cae817aa7c15fc0c2fc date1 = fallback; } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d49790396918 100644 +index 48d1444fbad1c57738807d0128b94160a5a17a4d..3f3d3cfa046124197bf7ed8d7f4b651bf8a73416 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -139,10 +139,10 @@ public abstract class PlayerList { - public static final Component CHAT_FILTERED_FULL = Component.translatable("chat.filtered_full"); +@@ -133,10 +133,10 @@ public abstract class PlayerList { + public static final Component DUPLICATE_LOGIN_DISCONNECT_MESSAGE = Component.translatable("multiplayer.disconnect.duplicate_login"); private static final Logger LOGGER = LogUtils.getLogger(); private static final int SEND_PLAYER_INFO_INTERVAL = 600; - private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); @@ -16263,7 +16032,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 private final UserBanList bans; private final IpBanList ipBans; private final ServerOpList ops; -@@ -164,9 +164,56 @@ public abstract class PlayerList { +@@ -157,9 +157,56 @@ public abstract class PlayerList { // CraftBukkit start private CraftServer cserver; @@ -16321,16 +16090,16 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 public PlayerList(MinecraftServer server, LayeredRegistryAccess registryManager, PlayerDataStorage saveHandler, int maxPlayers) { this.cserver = server.server = new CraftServer((DedicatedServer) server, this); server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper -@@ -188,7 +235,7 @@ public abstract class PlayerList { +@@ -180,7 +227,7 @@ public abstract class PlayerList { } abstract public void loadAndSaveFiles(); // Paper - moved from DedicatedPlayerList constructor -- public void placeNewPlayer(Connection connection, ServerPlayer player) { -+ public void loadSpawnForNewPlayer(Connection connection, ServerPlayer player, org.apache.commons.lang3.mutable.MutableObject data, org.apache.commons.lang3.mutable.MutableObject lastKnownName, ca.spottedleaf.concurrentutil.completable.Completable toComplete) { +- public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { ++ public void loadSpawnForNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie clientData, org.apache.commons.lang3.mutable.MutableObject data, org.apache.commons.lang3.mutable.MutableObject lastKnownName, ca.spottedleaf.concurrentutil.completable.Completable toComplete) { // Folia - region threading - rewrite login process player.isRealPlayer = true; // Paper player.loginTime = System.currentTimeMillis(); // Paper GameProfile gameprofile = player.getGameProfile(); -@@ -248,9 +295,30 @@ public abstract class PlayerList { +@@ -240,16 +287,37 @@ public abstract class PlayerList { // Paper start if (nbttagcompound == null) { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login @@ -16339,6 +16108,8 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } // Paper end + // Folia start - region threading - rewrite login process ++ data.setValue(nbttagcompound); ++ lastKnownName.setValue(s); + if (nbttagcompound != null) { + worldserver1.loadChunksForMoveAsync( + player.getBoundingBox(), @@ -16348,21 +16119,18 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 + } + ); + } -+ data.setValue(nbttagcompound); -+ lastKnownName.setValue(s); + return; + } + // nbttagcomound -> player data + // s -> last known name -+ public void placeNewPlayer(Connection connection, ServerPlayer player, CompoundTag nbttagcompound, String s, Location selectedSpawn) { ++ public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData, CompoundTag nbttagcompound, String s, Location selectedSpawn) { + ServerLevel worldserver1 = ((CraftWorld)selectedSpawn.getWorld()).getHandle(); + player.setPosRaw(selectedSpawn.getX(), selectedSpawn.getY(), selectedSpawn.getZ()); + player.lastSave = System.nanoTime(); // changed to nanoTime + // Folia end - region threading - rewrite login process player.setServerLevel(worldserver1); - String s1 = "local"; + String s1 = connection.getLoggableAddress(this.server.logIPs()); -@@ -261,7 +329,7 @@ public abstract class PlayerList { // Spigot start - spawn location event Player spawnPlayer = player.getBukkitEntity(); org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.getLocation()); // Paper use our duplicate event @@ -16371,15 +16139,18 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 Location loc = ev.getSpawnLocation(); worldserver1 = ((CraftWorld) loc.getWorld()).getHandle(); -@@ -280,6 +348,7 @@ public abstract class PlayerList { +@@ -268,6 +336,10 @@ public abstract class PlayerList { player.loadGameTypes(nbttagcompound); - ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player); -+ worldserver1.getCurrentWorldData().connections.add(connection); // Folia - region threading - only AFTER updating listener to game + ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData); ++ // Folia start - rewrite login process ++ // only after setting the connection listener to game type, add the connection to this regions list ++ worldserver1.getCurrentWorldData().connections.add(connection); ++ // Folia end - rewrite login process GameRules gamerules = worldserver1.getGameRules(); boolean flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN); boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); -@@ -297,7 +366,7 @@ public abstract class PlayerList { +@@ -283,7 +355,7 @@ public abstract class PlayerList { this.sendPlayerPermissionLevel(player); player.getStats().markAllDirty(); player.getRecipeBook().sendInitialRecipeBook(player); @@ -16388,7 +16159,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 this.server.invalidateStatus(); MutableComponent ichatmutablecomponent; -@@ -339,7 +408,7 @@ public abstract class PlayerList { +@@ -325,7 +397,7 @@ public abstract class PlayerList { this.cserver.getPluginManager().callEvent(playerJoinEvent); if (!player.connection.isAcceptingMessages()) { @@ -16397,7 +16168,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage(); -@@ -354,8 +423,7 @@ public abstract class PlayerList { +@@ -340,8 +412,7 @@ public abstract class PlayerList { ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper final List onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - use single player info update packet @@ -16407,7 +16178,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) { // Paper start -@@ -480,7 +548,7 @@ public abstract class PlayerList { +@@ -463,7 +534,7 @@ public abstract class PlayerList { // Paper start - Add to collideRule team if needed final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard(); final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName); @@ -16416,7 +16187,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); } // Paper end -@@ -571,7 +639,7 @@ public abstract class PlayerList { +@@ -558,7 +629,7 @@ public abstract class PlayerList { protected void save(ServerPlayer player) { if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit @@ -16425,7 +16196,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 this.playerIo.save(player); ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit -@@ -611,7 +679,7 @@ public abstract class PlayerList { +@@ -598,7 +669,7 @@ public abstract class PlayerList { // CraftBukkit end // Paper start - Remove from collideRule team if needed @@ -16434,7 +16205,16 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 final Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard(); final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName); if (entityplayer.getTeam() == team && team != null) { -@@ -670,8 +738,7 @@ public abstract class PlayerList { +@@ -638,7 +709,7 @@ public abstract class PlayerList { + + entityplayer.unRide(); + worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER); +- entityplayer.retireScheduler(); // Paper - Folia schedulers ++ // Folia - region threading - move to onDisconnect of common packet listener + entityplayer.getAdvancements().stopListening(); + this.players.remove(entityplayer); + this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot +@@ -657,8 +728,7 @@ public abstract class PlayerList { // CraftBukkit start // this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID()))); ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID())); @@ -16444,7 +16224,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 if (entityplayer2.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) { entityplayer2.connection.send(packet); -@@ -696,19 +763,13 @@ public abstract class PlayerList { +@@ -683,19 +753,13 @@ public abstract class PlayerList { ServerPlayer entityplayer; @@ -16466,7 +16246,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } // Instead of kicking then returning, we need to store the kick reason -@@ -727,7 +788,7 @@ public abstract class PlayerList { +@@ -714,7 +778,7 @@ public abstract class PlayerList { ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); if (gameprofilebanentry.getExpires() != null) { @@ -16475,7 +16255,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } // return chatmessage; -@@ -740,14 +801,14 @@ public abstract class PlayerList { +@@ -727,14 +791,14 @@ public abstract class PlayerList { ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipbanentry.getReason()); if (ipbanentry.getExpires() != null) { @@ -16484,7 +16264,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } // return chatmessage; - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure + event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure } else { // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; - if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) { @@ -16492,7 +16272,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure } } -@@ -805,6 +866,11 @@ public abstract class PlayerList { +@@ -800,6 +864,11 @@ public abstract class PlayerList { public ServerPlayer respawn(ServerPlayer entityplayer, ServerLevel worldserver, boolean flag, Location location, boolean avoidSuffocation, RespawnReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag...respawnFlags) { // Paper end @@ -16504,7 +16284,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 entityplayer.stopRiding(); // CraftBukkit this.players.remove(entityplayer); this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -@@ -999,10 +1065,10 @@ public abstract class PlayerList { +@@ -993,10 +1062,10 @@ public abstract class PlayerList { public void tick() { if (++this.sendAllPlayerInfoIn > 600) { // CraftBukkit start @@ -16518,7 +16298,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 @Override public boolean test(ServerPlayer input) { return target.getBukkitEntity().canSee(input.getBukkitEntity()); -@@ -1028,18 +1094,17 @@ public abstract class PlayerList { +@@ -1022,18 +1091,17 @@ public abstract class PlayerList { // CraftBukkit start - add a world/entity limited version public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) { @@ -16541,7 +16321,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } } -@@ -1083,8 +1148,7 @@ public abstract class PlayerList { +@@ -1077,8 +1145,7 @@ public abstract class PlayerList { if (scoreboardteambase == null) { this.broadcastSystemMessage(message, false); } else { @@ -16551,7 +16331,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 if (entityplayer.getTeam() != scoreboardteambase) { entityplayer.sendSystemMessage(message); -@@ -1095,10 +1159,12 @@ public abstract class PlayerList { +@@ -1089,10 +1156,12 @@ public abstract class PlayerList { } public String[] getPlayerNamesArray() { @@ -16567,7 +16347,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } return astring; -@@ -1117,7 +1183,9 @@ public abstract class PlayerList { +@@ -1111,7 +1180,9 @@ public abstract class PlayerList { ServerPlayer entityplayer = this.getPlayer(profile.getId()); if (entityplayer != null) { @@ -16577,7 +16357,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } } -@@ -1127,7 +1195,10 @@ public abstract class PlayerList { +@@ -1121,7 +1192,10 @@ public abstract class PlayerList { ServerPlayer entityplayer = this.getPlayer(profile.getId()); if (entityplayer != null) { @@ -16588,7 +16368,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } } -@@ -1188,8 +1259,7 @@ public abstract class PlayerList { +@@ -1182,8 +1256,7 @@ public abstract class PlayerList { } public void broadcast(@Nullable net.minecraft.world.entity.player.Player player, double x, double y, double z, double distance, ResourceKey worldKey, Packet packet) { @@ -16598,7 +16378,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 // CraftBukkit start - Test if player receiving packet can see the source of the packet if (player != null && !entityplayer.getBukkitEntity().canSee(player.getBukkitEntity())) { -@@ -1219,12 +1289,21 @@ public abstract class PlayerList { +@@ -1213,12 +1286,21 @@ public abstract class PlayerList { io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main MinecraftTimings.savePlayers.startTiming(); // Paper int numSaved = 0; @@ -16625,17 +16405,17 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 } // Paper end } -@@ -1341,6 +1420,20 @@ public abstract class PlayerList { +@@ -1335,6 +1417,20 @@ public abstract class PlayerList { } public void removeAll(boolean isRestarting) { + // Folia start - region threading + // just send disconnect packet, don't modify state + for (ServerPlayer player : this.players) { -+ final Component shutdownMessage = PaperAdventure.asVanilla(this.server.server.shutdownMessage()); // Paper - Adventure ++ final Component shutdownMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(this.server.server.shutdownMessage()); // Paper - Adventure + // CraftBukkit end + -+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundDisconnectPacket(shutdownMessage), net.minecraft.network.PacketSendListener.thenRun(() -> { ++ player.connection.send(new net.minecraft.network.protocol.common.ClientboundDisconnectPacket(shutdownMessage), net.minecraft.network.PacketSendListener.thenRun(() -> { + player.connection.connection.disconnect(shutdownMessage); + })); + } @@ -16646,7 +16426,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 // Paper end // CraftBukkit start - disconnect safely for (ServerPlayer player : this.players) { -@@ -1350,7 +1443,7 @@ public abstract class PlayerList { +@@ -1344,7 +1440,7 @@ public abstract class PlayerList { // CraftBukkit end // Paper start - Remove collideRule team if it exists @@ -16656,7 +16436,7 @@ index f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f..82c7235ad9f4bc4a9f6e018c9905d497 final PlayerTeam team = scoreboard.getPlayersTeam(this.collideRuleTeamName); if (team != null) scoreboard.removePlayerTeam(team); diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java -index 9e8112fbc40a1d89c0f73ea4452e0fa1bb459bf4..f8fab664088a4adfcea0b37e45b80fa85d18bfb0 100644 +index 09fc086548b9d0f97849f56f41e3a5be87f5091a..4dfb52f7fde8603b9fc236ea57e9b768a9d04fc6 100644 --- a/src/main/java/net/minecraft/server/players/StoredUserList.java +++ b/src/main/java/net/minecraft/server/players/StoredUserList.java @@ -143,6 +143,7 @@ public abstract class StoredUserList> { @@ -16680,7 +16460,7 @@ index 9e8112fbc40a1d89c0f73ea4452e0fa1bb459bf4..f8fab664088a4adfcea0b37e45b80fa8 if (this.file.exists()) { BufferedReader bufferedreader = Files.newReader(this.file, StandardCharsets.UTF_8); -@@ -221,5 +224,6 @@ public abstract class StoredUserList> { +@@ -233,5 +236,6 @@ public abstract class StoredUserList> { } } @@ -16755,7 +16535,7 @@ index 028d69907a988e191213a17e072ef22710b5bc83..ffa081156313247882747ea6da182ee5 } } diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index c12d7bacf2c54f268b1bc5e46250a083ca041415..08e84a81facb5514b4e26805dda1291db8936f1a 100644 +index 9c99b2e365aacb8309f29acb9025faccd2c676b3..d02bc26812321745795d2f0bc3705addd0be912d 100644 --- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java +++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java @@ -52,7 +52,7 @@ public class CombatTracker { @@ -16810,10 +16590,10 @@ index ea27b46eec01bda427653335f922ccd068cffcb5..e551d3b875eab6851b75041f418c9a08 return blockToFallLocation(blockState); } else { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217dcc084882 100644 +index f20ae9153b7098980ce6c0e75fcbbb4da652661b..47061546345d0f367aa64c2d562a53509829d499 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -166,7 +166,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -165,7 +165,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { // Paper start public static RandomSource SHARED_RANDOM = new RandomRandomSource(); @@ -16822,7 +16602,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d private boolean locked = false; @Override -@@ -240,7 +240,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -239,7 +239,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper public boolean collisionLoadChunks = false; // Paper @@ -16831,37 +16611,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d public @org.jetbrains.annotations.Nullable net.minecraft.server.level.ChunkMap.TrackedEntity tracker; // Paper public @Nullable Throwable addedToWorldStack; // Paper - entity debug -@@ -508,28 +508,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { - this.isLegacyTrackingEntity = isLegacyTrackingEntity; - } - -- public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayersInTrackRange() { -- // determine highest range of passengers -- if (this.passengers.isEmpty()) { -- return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()] -- .getObjectsInRange(MCUtil.getCoordinateKey(this)); -- } -- Iterable passengers = this.getIndirectPassengers(); -- net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap; -- org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType; -- int range = chunkMap.getEntityTrackerRange(type.ordinal()); -- -- for (Entity passenger : passengers) { -- org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType; -- int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal()); -- if (passengerRange > range) { -- type = passengerType; -- range = passengerRange; -- } -- } -- -- return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this)); -- } -+ // Folia - region threading - // Paper end - optimise entity tracking - // Paper start - make end portalling safe - public BlockPos portalBlock; -@@ -561,6 +540,25 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -528,6 +528,25 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { this.teleportTo(worldserver, null); } // Paper end - make end portalling safe @@ -16887,7 +16637,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -803,6 +801,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -770,6 +789,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { // CraftBukkit start public void postTick() { @@ -16900,7 +16650,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d // No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities this.handleNetherPortal(); -@@ -825,7 +829,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -792,7 +817,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { this.walkDistO = this.walkDist; this.xRotO = this.getXRot(); this.yRotO = this.getYRot(); @@ -16909,7 +16659,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } -@@ -934,11 +938,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -901,11 +926,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { // This will be called every single tick the entity is in lava, so don't throw an event this.setSecondsOnFire(15, false); } @@ -16923,7 +16673,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d // CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls } -@@ -1083,8 +1087,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -1050,8 +1075,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { } else { this.wasOnFire = this.isOnFire(); if (movementType == MoverType.PISTON) { @@ -16934,7 +16684,25 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d movement = this.limitPistonMovement(movement); if (movement.equals(Vec3.ZERO)) { return; -@@ -3213,6 +3217,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -2934,7 +2959,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + this.passengers = ImmutableList.copyOf(list); + } + +- this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); ++ if (!passenger.hasNullCallback()) this.gameEvent(GameEvent.ENTITY_MOUNT, passenger); // Folia - region threading - do not fire game events for entities not added + } + } + +@@ -2983,7 +3008,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + } + + entity.boardingCooldown = 60; +- this.gameEvent(GameEvent.ENTITY_DISMOUNT, entity); ++ if (!entity.hasNullCallback()) this.gameEvent(GameEvent.ENTITY_DISMOUNT, entity); // Folia - region threading - do not fire game events for entities not added + } + return true; // CraftBukkit + } +@@ -3263,6 +3288,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { @Nullable public Team getTeam() { @@ -16946,7 +16714,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName()); } -@@ -3328,9 +3337,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -3378,9 +3408,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { if (this.fireImmune()) { return; } @@ -16958,7 +16726,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d return; } // CraftBukkit end -@@ -3503,6 +3512,775 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -3553,6 +3583,775 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { this.portalEntrancePos = original.portalEntrancePos; } @@ -17734,10 +17502,10 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d @Nullable public Entity changeDimension(ServerLevel destination) { // CraftBukkit start -@@ -3511,6 +4289,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -3561,6 +4360,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { @Nullable - public Entity teleportTo(ServerLevel worldserver, PositionImpl location) { + public Entity teleportTo(ServerLevel worldserver, Vec3 location) { + // Folia start - region threading + if (true) { + throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); @@ -17746,7 +17514,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d // CraftBukkit end // Paper start - fix bad state entities causing dupes if (!this.isAlive() || !this.valid) { -@@ -3599,6 +4382,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -3649,6 +4453,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { } } @@ -17759,7 +17527,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d protected void removeAfterChangingDimensions() { this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION); } -@@ -4536,7 +5325,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -4577,7 +5387,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { } } // Paper end - fix MC-4 @@ -17769,7 +17537,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d synchronized (this.posLock) { // Paper this.position = new Vec3(x, y, z); } // Paper -@@ -4557,7 +5347,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -4598,7 +5409,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { // Paper start - never allow AABB to become desynced from position // hanging has its own special logic @@ -17778,7 +17546,7 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d this.setBoundingBox(this.makeBoundingBox()); } // Paper end -@@ -4644,6 +5434,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -4685,6 +5496,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { return this.removalReason != null; } @@ -17791,8 +17559,29 @@ index e8485fb900b25e911a858678a833852731cb2ace..71830b5fbeda3c7c63460c7cee05217d @Nullable public Entity.RemovalReason getRemovalReason() { return this.removalReason; +@@ -4700,6 +5517,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + } + // Paper end - rewrite chunk system + final boolean alreadyRemoved = this.removalReason != null; ++ // Folia start - region threading ++ this.preRemove(reason); ++ // Folia end - region threading + if (this.removalReason == null) { + this.removalReason = reason; + } +@@ -4722,6 +5542,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + this.removalReason = null; + } + ++ // Folia start - region threading ++ protected void preRemove(Entity.RemovalReason reason) {} ++ // Folia end - region threading ++ + // Paper start - Folia schedulers + /** + * Invoked only when the entity is truly removed from the server, never to be added to any world. diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 7763450e85146d43fcf84d380d0e7a8183d83747..50e1390f455cf8e6da9153760f32ccb81aa20bd1 100644 +index c039c77d0dd6ec1d336948ca6b5351d6fae1d8bb..a4f2d8cc7ca428c276ad509f34c02370b13d60a3 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -276,6 +276,13 @@ public abstract class LivingEntity extends Entity implements Attackable { @@ -17856,7 +17645,7 @@ index 7763450e85146d43fcf84d380d0e7a8183d83747..50e1390f455cf8e6da9153760f32ccb8 if (this.isTickingEffects) { this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); return true; -@@ -2300,7 +2310,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2334,7 +2344,7 @@ public abstract class LivingEntity extends Entity implements Attackable { @Nullable public LivingEntity getKillCredit() { @@ -17865,7 +17654,7 @@ index 7763450e85146d43fcf84d380d0e7a8183d83747..50e1390f455cf8e6da9153760f32ccb8 } public final float getMaxHealth() { -@@ -3436,7 +3446,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3465,7 +3475,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.pushEntities(); this.level().getProfiler().pop(); // Paper start @@ -17874,7 +17663,7 @@ index 7763450e85146d43fcf84d380d0e7a8183d83747..50e1390f455cf8e6da9153760f32ccb8 if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); Location to = new Location (this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); -@@ -4102,7 +4112,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4159,7 +4169,7 @@ public abstract class LivingEntity extends Entity implements Attackable { BlockPos blockposition = BlockPos.containing(d0, d1, d2); Level world = this.level(); @@ -17884,10 +17673,10 @@ index 7763450e85146d43fcf84d380d0e7a8183d83747..50e1390f455cf8e6da9153760f32ccb8 while (!flag2 && blockposition.getY() > world.getMinBuildHeight()) { diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f72cf8afc 100644 +index d28c477171c1b6888a45175075017d960464b5cd..8d6a2966ebf5ff5813575f5451cceaddace53b4c 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -134,6 +134,14 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -136,6 +136,14 @@ public abstract class Mob extends LivingEntity implements Targeting { public boolean aware = true; // CraftBukkit @@ -17902,7 +17691,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f protected Mob(EntityType type, Level world) { super(type, world); this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -286,9 +294,21 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -287,9 +295,21 @@ public abstract class Mob extends LivingEntity implements Targeting { @Nullable @Override public LivingEntity getTarget() { @@ -17924,7 +17713,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f public org.bukkit.craftbukkit.entity.CraftMob getBukkitMob() { return (org.bukkit.craftbukkit.entity.CraftMob) super.getBukkitEntity(); } // Paper public void setTarget(@Nullable LivingEntity target) { // CraftBukkit start - fire event -@@ -296,7 +316,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -297,7 +317,7 @@ public abstract class Mob extends LivingEntity implements Targeting { } public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { @@ -17933,21 +17722,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f if (fireEvent) { if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && entityliving == null) { reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; -@@ -858,12 +878,7 @@ public abstract class Mob extends LivingEntity implements Targeting { - if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { - this.discard(); - } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { -- // Paper start - optimise checkDespawn -- Player entityhuman = this.level().findNearbyPlayer(this, level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()).hard() + 1, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper -- if (entityhuman == null) { -- entityhuman = ((ServerLevel)this.level()).playersAffectingSpawning.isEmpty() ? null : ((ServerLevel)this.level()).playersAffectingSpawning.get(0); -- } -- // Paper end - optimise checkDespawn -+ Player entityhuman = this.level().getNearestPlayer(this, -1.0D); // Folia - region threading - - if (entityhuman != null) { - double d0 = entityhuman.distanceToSqr((Entity) this); -@@ -906,7 +921,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -909,7 +929,7 @@ public abstract class Mob extends LivingEntity implements Targeting { this.level().getProfiler().push("sensing"); this.sensing.tick(); this.level().getProfiler().pop(); @@ -17956,7 +17731,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f if (i % 2 != 0 && this.tickCount > 1) { this.level().getProfiler().push("targetSelector"); -@@ -1730,6 +1745,15 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1746,6 +1766,15 @@ public abstract class Mob extends LivingEntity implements Targeting { this.goalSelector.removeAllGoals(predicate); } @@ -17972,7 +17747,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f @Override protected void removeAfterChangingDimensions() { super.removeAfterChangingDimensions(); -@@ -1738,12 +1762,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1754,12 +1783,7 @@ public abstract class Mob extends LivingEntity implements Targeting { this.level().getCraftServer().getPluginManager().callEvent(event); // CraftBukkit this.dropLeash(true, event.isDropLeash()); // Paper end @@ -17987,7 +17762,7 @@ index e2a25c29ec74147b3e66aa0b3deb85a8f6ee53a5..a21edc7df32a59a6cb1af3865d2ce35f @Nullable diff --git a/src/main/java/net/minecraft/world/entity/ai/Brain.java b/src/main/java/net/minecraft/world/entity/ai/Brain.java -index a2de99709ce14303a309806c683da6b3548659c1..082b0594d5de2e952e0b2b64e76c1db3ddba82b9 100644 +index 21e5d1451f90194aa415cf0a183d1a731854f605..c83e9f99f8f3e1b147b1a5122651540dc86abdff 100644 --- a/src/main/java/net/minecraft/world/entity/ai/Brain.java +++ b/src/main/java/net/minecraft/world/entity/ai/Brain.java @@ -412,9 +412,17 @@ public class Brain { @@ -18026,7 +17801,7 @@ index 8ec07578c1e41997a2e5ef158885ad3f4c2a31b6..003d85261bc0df871a8247c193e2b45c context.>get(mobs).stream().filter((mob) -> { return mob instanceof Villager && mob != entity; diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -index 8e1c60d3622bf069feec5e636d2a5b4257e11776..9d058297c9711a9ce71a99b1e9289ae14ae4580f 100644 +index 689bbc0feb700cfd6b10601d2c5a237ec40ed756..4fa58570d9124ffd7dd94499f03a844e30ead864 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java @@ -70,7 +70,7 @@ public class FollowOwnerGoal extends Goal { @@ -18083,23 +17858,23 @@ index 8e1c60d3622bf069feec5e636d2a5b4257e11776..9d058297c9711a9ce71a99b1e9289ae1 this.navigation.stop(); return true; diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -index 71934af2dc4d209a9fbccfd36b5f2815ec196892..ef5f231ca2ac2837609670e84d9571eb8f80126e 100644 +index ac996b066415e461af1fcb71b19807401179c7f8..c065d372ac5f1663db3c521e996ee03669d0bc31 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -@@ -40,6 +40,11 @@ public class GroundPathNavigation extends PathNavigation { +@@ -42,6 +42,11 @@ public class GroundPathNavigation extends PathNavigation { @Override public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper + // Folia start - region threading -+ if (!io.papermc.paper.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)this.level, target) || this.level.getChunkIfLoaded(target) == null) { ++ if (!io.papermc.paper.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)this.level, target)) { + return null; + } + // Folia end - region threading - if (this.level.getBlockState(target).isAir()) { - BlockPos blockPos; - for(blockPos = target.below(); blockPos.getY() > this.level.getMinBuildHeight() && this.level.getBlockState(blockPos).isAir(); blockPos = blockPos.below()) { + LevelChunk levelChunk = this.level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(target.getX()), SectionPos.blockToSectionCoord(target.getZ())); + if (levelChunk == null) { + return null; diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index b376670d11088e524ce246f667e580e90cd119a3..2549b81eb5fa1a021edac960170f5e0d513dae97 100644 +index b37415d45dda8e658c8995a4519e552dc378bb41..147057bfd67d56857b5d3ab1ebd0f0a0c1793a9c 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -80,11 +80,11 @@ public abstract class PathNavigation { @@ -18148,7 +17923,7 @@ index e3242cf9a6ad51a23c5781142198dec30c8f376d..f32f5982ceb368b240062b9b8ac0141b }).filter((entityplayer) -> { return entity.closerThan(entityplayer, 10.0D); diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java -index fed09b886f4fa0006d160e5f2abb00dfee45434d..69075026c25ed1ce0f3c769ea0e4a8f3c4841f63 100644 +index fed09b886f4fa0006d160e5f2abb00dfee45434d..37a86fe9585ebf004876a48808e19eb272e2372d 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java @@ -22,62 +22,66 @@ import org.slf4j.Logger; @@ -18258,7 +18033,7 @@ index fed09b886f4fa0006d160e5f2abb00dfee45434d..69075026c25ed1ce0f3c769ea0e4a8f3 break; } } -@@ -108,7 +112,8 @@ public class VillageSiege implements CustomSpawner { +@@ -108,13 +112,15 @@ public class VillageSiege implements CustomSpawner { } private void trySpawn(ServerLevel world) { @@ -18268,7 +18043,23 @@ index fed09b886f4fa0006d160e5f2abb00dfee45434d..69075026c25ed1ce0f3c769ea0e4a8f3 if (vec3d != null) { Zombie entityzombie; -@@ -143,7 +148,7 @@ public class VillageSiege implements CustomSpawner { + + try { + entityzombie = new Zombie(world); ++ entityzombie.moveTo(vec3d.x, vec3d.y, vec3d.z, world.random.nextFloat() * 360.0F, 0.0F); // Folia - region threading - move up + entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null); + } catch (Exception exception) { + VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception); +@@ -122,7 +128,7 @@ public class VillageSiege implements CustomSpawner { + return; + } + +- entityzombie.moveTo(vec3d.x, vec3d.y, vec3d.z, world.random.nextFloat() * 360.0F, 0.0F); ++ // Folia - region threading - move up + world.addFreshEntityWithPassengers(entityzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit + } + } +@@ -143,7 +149,7 @@ public class VillageSiege implements CustomSpawner { return null; } @@ -18345,10 +18136,10 @@ index 55026e1731e41b4e3e4c6a8fef5d96a32051a556..a5ae46b30c24812f5e3ef66eb748e92f } diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 90ce201bc7c47cef9bc59d7b535a7453854bac75..9c7c116a7d3570ccf5b30d55d68c420fec0d8ab5 100644 +index de51ce9875e12961e6e549e87d76f492d2f19787..8c9470bc0dd2d1a5bfbdc4921f4063bdfccd6924 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Cat.java +++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -363,7 +363,7 @@ public class Cat extends TamableAnimal implements VariantHolder { +@@ -364,7 +364,7 @@ public class Cat extends TamableAnimal implements VariantHolder { }); ServerLevel worldserver = world.getLevel(); @@ -18358,10 +18149,10 @@ index 90ce201bc7c47cef9bc59d7b535a7453854bac75..9c7c116a7d3570ccf5b30d55d68c420f this.setPersistenceRequired(); } diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index d3c15d029d5f003cba3c89f7ea1f3ed4f943f2bd..5f0436a399178aa374a5178d5050ec6025180fac 100644 +index 490472bb618e9ac07da5883a71dff8920525b1e2..28b4be002978f26a3ff9901e9d3dbe860a7d7665 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java +++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -@@ -337,9 +337,9 @@ public class Turtle extends Animal { +@@ -341,9 +341,9 @@ public class Turtle extends Animal { @Override public void thunderHit(ServerLevel world, LightningBolt lightning) { @@ -18372,7 +18163,7 @@ index d3c15d029d5f003cba3c89f7ea1f3ed4f943f2bd..5f0436a399178aa374a5178d5050ec60 + org.bukkit.craftbukkit.event.CraftEventFactory.entityDamageRT.set(null); // CraftBukkit // Folia - region threading } - private static class TurtleMoveControl extends MoveControl { + @Override diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java index 759ecd79534a7706f7d4a63eb9dacbefcfe54674..0344b1f77f23274c2932b5dce01b0ea6887078cf 100644 --- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java @@ -18389,7 +18180,7 @@ index 759ecd79534a7706f7d4a63eb9dacbefcfe54674..0344b1f77f23274c2932b5dce01b0ea6 }); diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 18eaccb39a4c81338a8cbebe3de03934913ac2a4..34b3541603b8cca16c7d62f3981d7ce3e8be0dbe 100644 +index 9105418b29c89f092378da11b14e3d324332a2ba..31b59d7d439dbbd79605e5d078cbc9131b786ad9 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -295,9 +295,9 @@ public class FallingBlockEntity extends Entity { @@ -18405,7 +18196,7 @@ index 18eaccb39a4c81338a8cbebe3de03934913ac2a4..34b3541603b8cca16c7d62f3981d7ce3 boolean flag = this.blockState.is(BlockTags.ANVIL); diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index d39f31e7cf315c7cdc1daab28164380e44dd8341..c213ef54c93b98837528c2d5ca45e6659cd43515 100644 +index eb0351aa12eebcefab1d1d14641fc3c60cbbcab8..ff4d2676a0833977dd8406d49dc0b5035c468b2d 100644 --- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java @@ -52,7 +52,7 @@ public class ItemEntity extends Entity implements TraceableEntity { @@ -18519,10 +18310,10 @@ index 4ce3e69970dd9eb251d0538a2d233ca30e9e5e47..acb7545a3346758c7a598b104ea7ae43 net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this); net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index 65cb385ab294e362d666a6d03c4496cdc3b64890..51c4125c4014511dc45e7e624dc190272442cb8a 100644 +index 90e577b1a89b02c38daff2845a63dafe5ed929e1..150fb1fc4d70330a4c56ff5847792a1eb84af633 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Vex.java +++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -354,7 +354,7 @@ public class Vex extends Monster implements TraceableEntity { +@@ -359,7 +359,7 @@ public class Vex extends Monster implements TraceableEntity { public void tick() { BlockPos blockposition = Vex.this.getBoundOrigin(); @@ -18532,10 +18323,10 @@ index 65cb385ab294e362d666a6d03c4496cdc3b64890..51c4125c4014511dc45e7e624dc19027 } diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -index 3f8c1d1d3c408fc4f15c4b5680bc22c86f104a9d..720278afd8c28c4303cc2fbfe5874a79d607f6ef 100644 +index 1ddbba72a5fd3d225b651815a38d178941fba289..483bf035ad9d278755f5a2c525f7e2ca4cc62211 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java -@@ -94,7 +94,7 @@ public class Zombie extends Monster { +@@ -95,7 +95,7 @@ public class Zombie extends Monster { private boolean canBreakDoors; private int inWaterTime; public int conversionTime; @@ -18544,7 +18335,7 @@ index 3f8c1d1d3c408fc4f15c4b5680bc22c86f104a9d..720278afd8c28c4303cc2fbfe5874a79 private boolean shouldBurnInDay = true; // Paper public Zombie(EntityType type, Level world) { -@@ -217,10 +217,7 @@ public class Zombie extends Monster { +@@ -218,10 +218,7 @@ public class Zombie extends Monster { public void tick() { if (!this.level().isClientSide && this.isAlive() && !this.isNoAi()) { if (this.isUnderWaterConverting()) { @@ -18556,7 +18347,7 @@ index 3f8c1d1d3c408fc4f15c4b5680bc22c86f104a9d..720278afd8c28c4303cc2fbfe5874a79 if (this.conversionTime < 0) { this.doUnderWaterConversion(); } -@@ -237,7 +234,7 @@ public class Zombie extends Monster { +@@ -238,7 +235,7 @@ public class Zombie extends Monster { } super.tick(); @@ -18565,7 +18356,7 @@ index 3f8c1d1d3c408fc4f15c4b5680bc22c86f104a9d..720278afd8c28c4303cc2fbfe5874a79 } @Override -@@ -276,7 +273,7 @@ public class Zombie extends Monster { +@@ -277,7 +274,7 @@ public class Zombie extends Monster { } // Paper end public void startUnderWaterConversion(int ticksUntilWaterConversion) { @@ -18575,10 +18366,10 @@ index 3f8c1d1d3c408fc4f15c4b5680bc22c86f104a9d..720278afd8c28c4303cc2fbfe5874a79 this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, true); } diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 25ed5571b24e590bc95056020d84496492b53298..3bf69b19227dafc442b24120c252bf597025a1ac 100644 +index 807cff3fb51269b97d9aecbcc4706f0a139dfeaa..145f7ea3b287ccd54dca9c5c284aaa251543ce64 100644 --- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -70,7 +70,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +@@ -73,7 +73,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { @Nullable private CompoundTag tradeOffers; private int villagerXp; @@ -18587,7 +18378,7 @@ index 25ed5571b24e590bc95056020d84496492b53298..3bf69b19227dafc442b24120c252bf59 public ZombieVillager(EntityType type, Level world) { super(type, world); -@@ -145,10 +145,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +@@ -148,10 +148,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { public void tick() { if (!this.level().isClientSide && this.isAlive() && this.isConverting()) { int i = this.getConversionProgress(); @@ -18599,7 +18390,7 @@ index 25ed5571b24e590bc95056020d84496492b53298..3bf69b19227dafc442b24120c252bf59 this.villagerConversionTime -= i; if (this.villagerConversionTime <= 0) { -@@ -157,7 +154,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +@@ -160,7 +157,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { } super.tick(); @@ -18609,10 +18400,10 @@ index 25ed5571b24e590bc95056020d84496492b53298..3bf69b19227dafc442b24120c252bf59 @Override diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index 564908ce0a560c2190fb624e77d227d3b7031024..1e1e79a9156d73299e27d70f76b39fd721346327 100644 +index 5119d070dbb04f5a4f9c2def526e33e15ca8573f..1cd031634150c7d5eb6cd7ba3c92a67c3d1dc0a5 100644 --- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java +++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -213,10 +213,18 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa +@@ -212,10 +212,18 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa this.readInventoryFromTag(nbt); } @@ -18661,10 +18452,10 @@ index 5f407535298a31a34cfe114dd863fd6a9b977707..cb0f75fb32836efa50f0a86dfae7907b return 0; } else { diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index e30d5ae3e2900f43d7cafde71b8196f26e872841..bcc1af431fb2da84ba00e87ae9491eb5f580e6de 100644 +index f555e29c7f9ea4ddb243a018bdc93d2bf1950c3c..a1bc0dc172fc88f87b4cd59a70c46331413d585f 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -202,7 +202,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -203,7 +203,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler brain.setCoreActivities(ImmutableSet.of(Activity.CORE)); brain.setDefaultActivity(Activity.IDLE); brain.setActiveActivityIfPossible(Activity.IDLE); @@ -18673,7 +18464,7 @@ index e30d5ae3e2900f43d7cafde71b8196f26e872841..bcc1af431fb2da84ba00e87ae9491eb5 } @Override -@@ -728,6 +728,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -729,6 +729,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler ServerLevel worldserver = minecraftserver.getLevel(globalpos.dimension()); if (worldserver != null) { @@ -18682,7 +18473,7 @@ index e30d5ae3e2900f43d7cafde71b8196f26e872841..bcc1af431fb2da84ba00e87ae9491eb5 PoiManager villageplace = worldserver.getPoiManager(); Optional> optional = villageplace.getType(globalpos.pos()); BiPredicate> bipredicate = (BiPredicate) Villager.POI_MEMORIES.get(pos); -@@ -736,6 +738,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler +@@ -737,6 +739,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler villageplace.release(globalpos.pos()); DebugPackets.sendPoiTicketCountPacket(worldserver, globalpos.pos()); } @@ -18783,8 +18574,27 @@ index 8385eb1d60f377da94e3178ab506feefb43563fd..2f57e5025d0a0e720f49da1e5231a7d9 // entityvillagertrader.setDespawnDelay(48000); // CraftBukkit - moved to EntityVillagerTrader constructor. This lets the value be modified by plugins on CreatureSpawnEvent entityvillagertrader.setWanderTarget(blockposition1); entityvillagertrader.restrictTo(blockposition1, 16); +diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java +index d58b4c0dbe651b5068212e5f14dce3164ee520f5..ea52f7b3620249a75cf9619481c90acdf781653e 100644 +--- a/src/main/java/net/minecraft/world/entity/player/Player.java ++++ b/src/main/java/net/minecraft/world/entity/player/Player.java +@@ -1508,6 +1508,14 @@ public abstract class Player extends LivingEntity { + + } + ++ // Folia start - region threading ++ @Override ++ protected void preRemove(RemovalReason reason) { ++ super.preRemove(reason); ++ this.fishing = null; ++ } ++ // Folia end - region threading ++ + public boolean isLocalPlayer() { + return false; + } diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index fa885337085348308604e50049ecc5bb52023884..270b37a34de47bc9846442d58827e8ff5e35178c 100644 +index 8affdd74769aed9aa92a76ba539cd9d27208827c..cf1643ea51487caacf93712faa3c6fde6097f2ac 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java +++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java @@ -149,6 +149,11 @@ public abstract class AbstractArrow extends Projectile { @@ -18872,7 +18682,7 @@ index 288910fb168ddc5d3a61971778b8038a56772fa8..17dce984f28e7a47d28ec6d2c52af2d2 } } diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -index b8c238287e0639b578170c6fec0d4db5a1a59fe7..98e322e8833ecadcf3a19b42215e658671f77733 100644 +index a9eaa079a43bc8a5e81deaf6df5ce2f9c53cb319..1ad4623c6eb24f9615ac970edff0ae8fcf910f26 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java +++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java @@ -104,7 +104,7 @@ public class FishingHook extends Projectile { @@ -18892,6 +18702,38 @@ index b8c238287e0639b578170c6fec0d4db5a1a59fe7..98e322e8833ecadcf3a19b42215e6586 Vec3 vec3d = new Vec3((double) (-f3), (double) Mth.clamp(-(f5 / f4), -5.0F, 5.0F), (double) (-f2)); double d3 = vec3d.length(); +@@ -266,6 +267,11 @@ public class FishingHook extends Projectile { + } + + private boolean shouldStopFishing(net.minecraft.world.entity.player.Player player) { ++ // Folia start - region threading ++ if (!io.papermc.paper.util.TickThread.isTickThreadFor(player)) { ++ return true; ++ } ++ // Folia end - region threading + ItemStack itemstack = player.getMainHandItem(); + ItemStack itemstack1 = player.getOffhandItem(); + boolean flag = itemstack.is(Items.FISHING_ROD); +@@ -597,10 +603,18 @@ public class FishingHook extends Projectile { + + @Override + public void remove(Entity.RemovalReason reason) { +- this.updateOwnerInfo((FishingHook) null); ++ // Folia - region threading - move into preRemove + super.remove(reason); + } + ++ // Folia start - region threading ++ @Override ++ protected void preRemove(RemovalReason reason) { ++ super.preRemove(reason); ++ this.updateOwnerInfo((FishingHook) null); ++ } ++ // Folia end - region threading ++ + @Override + public void onClientRemoval() { + this.updateOwnerInfo((FishingHook) null); diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java index 0bbe853f7df93f9dcd2b21d762939f8b6be069aa..4f4d6dedb99feac995e9b5bdf1d5c9f1332d61be 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java @@ -18909,10 +18751,10 @@ index 0bbe853f7df93f9dcd2b21d762939f8b6be069aa..4f4d6dedb99feac995e9b5bdf1d5c9f1 HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 1b7cf6d06bdf36f146656727511a461f2520762e..5835a1ba3e2927c6b5d143506b440ac5a43aaaa4 100644 +index a90317100d32974e481e14476843f66997a2cf3a..0c8f90a904c01105ba5fa6a8037150697bc2621e 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -62,9 +62,20 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -69,9 +69,20 @@ public abstract class Projectile extends Entity implements TraceableEntity { } // Paper end @@ -18933,7 +18775,7 @@ index 1b7cf6d06bdf36f146656727511a461f2520762e..5835a1ba3e2927c6b5d143506b440ac5 if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) { this.refreshProjectileSource(false); // Paper return this.cachedOwner; -@@ -289,6 +300,6 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -296,6 +307,6 @@ public abstract class Projectile extends Entity implements TraceableEntity { public boolean mayInteract(Level world, BlockPos pos) { Entity entity = this.getOwner(); @@ -18971,10 +18813,10 @@ index ab777952bda1651796ed41e8a7fc6621f27db9aa..6b9365eba3339578ee2984605240b74d boolean flag = false; diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -index e8114d89a3129e56c0329410a49ded63cc77cb4c..f1d291165fe6cb4160801d9bf2952e06a81287f9 100644 +index e02d5dcbf69bd68b2f567c1a16a44ab59955f871..7a679c45cccf3cffaaa4b813c928578c720198b1 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -43,6 +43,62 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { +@@ -42,6 +42,62 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { entityHitResult.getEntity().hurt(this.damageSources().thrown(this, this.getOwner()), 0.0F); } @@ -19037,7 +18879,7 @@ index e8114d89a3129e56c0329410a49ded63cc77cb4c..f1d291165fe6cb4160801d9bf2952e06 @Override protected void onHit(HitResult hitResult) { super.onHit(hitResult); -@@ -52,6 +108,20 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { +@@ -51,6 +107,20 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { } if (!this.level().isClientSide && !this.isRemoved()) { @@ -19058,7 +18900,7 @@ index e8114d89a3129e56c0329410a49ded63cc77cb4c..f1d291165fe6cb4160801d9bf2952e06 Entity entity = this.getOwner(); if (entity instanceof ServerPlayer) { -@@ -83,9 +153,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { +@@ -82,9 +152,9 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { entityplayer.connection.teleport(teleEvent.getTo()); entity.resetFallDistance(); @@ -19070,7 +18912,7 @@ index e8114d89a3129e56c0329410a49ded63cc77cb4c..f1d291165fe6cb4160801d9bf2952e06 } // CraftBukkit end } -@@ -111,6 +181,14 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { +@@ -110,6 +180,14 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { } @@ -19086,10 +18928,10 @@ index e8114d89a3129e56c0329410a49ded63cc77cb4c..f1d291165fe6cb4160801d9bf2952e06 @Override public Entity changeDimension(ServerLevel destination) { diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java -index f7399737548483905f3b5c08a03876b0da54b714..113583d0d9de744e314bc7ee15cb8e21ec4a92f9 100644 +index eaa2943b667967f93f28d9d794d702fdaeb670ec..8fc22de1aa17cd8cb52d3804533d56cbb0e6bfeb 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raid.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java -@@ -108,6 +108,13 @@ public class Raid { +@@ -107,6 +107,13 @@ public class Raid { private int celebrationTicks; private Optional waveSpawnPos; @@ -19103,7 +18945,7 @@ index f7399737548483905f3b5c08a03876b0da54b714..113583d0d9de744e314bc7ee15cb8e21 public Raid(int id, ServerLevel world, BlockPos pos) { this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); this.random = RandomSource.create(); -@@ -213,7 +220,7 @@ public class Raid { +@@ -215,7 +222,7 @@ public class Raid { return (entityplayer) -> { BlockPos blockposition = entityplayer.blockPosition(); @@ -19112,7 +18954,7 @@ index f7399737548483905f3b5c08a03876b0da54b714..113583d0d9de744e314bc7ee15cb8e21 }; } -@@ -527,7 +534,7 @@ public class Raid { +@@ -531,7 +538,7 @@ public class Raid { boolean flag = true; Collection collection = this.raidEvent.getPlayers(); long i = this.random.nextLong(); @@ -19122,7 +18964,7 @@ index f7399737548483905f3b5c08a03876b0da54b714..113583d0d9de744e314bc7ee15cb8e21 while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java -index 57fdcdaf54fd1c92a6e51a3a81789029096e5abe..c98e8a7d2aacf446a9770970b4d932d507db78b4 100644 +index cdbc925ef61b8b439415f0a89368227890bcecb2..6ad770b8ea068638c31a3a04fbbd84ddd294bb3c 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raider.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java @@ -91,7 +91,7 @@ public abstract class Raider extends PatrollingMonster { @@ -19135,10 +18977,10 @@ index 57fdcdaf54fd1c92a6e51a3a81789029096e5abe..c98e8a7d2aacf446a9770970b4d932d5 if (raid1 != null && Raids.canJoinRaid(this, raid1)) { diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java -index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41b3dc5e8a 100644 +index 31831811ce16265e9828fa34d9e67d8ac195d723..287024eaee26390a469162d63045a7cb1bfc20cf 100644 --- a/src/main/java/net/minecraft/world/entity/raid/Raids.java +++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java -@@ -28,14 +28,14 @@ import net.minecraft.world.phys.Vec3; +@@ -29,9 +29,9 @@ import net.minecraft.world.phys.Vec3; public class Raids extends SavedData { private static final String RAID_FILE_ID = "raids"; @@ -19149,6 +18991,9 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 + private final java.util.concurrent.atomic.AtomicInteger nextAvailableID = new java.util.concurrent.atomic.AtomicInteger(); // Folia - make raids thread-safe private int tick; + public static SavedData.Factory factory(ServerLevel world) { +@@ -44,7 +44,7 @@ public class Raids extends SavedData { + public Raids(ServerLevel world) { this.level = world; - this.nextAvailableID = 1; @@ -19156,7 +19001,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 this.setDirty(); } -@@ -43,12 +43,26 @@ public class Raids extends SavedData { +@@ -52,12 +52,26 @@ public class Raids extends SavedData { return (Raid) this.raidMap.get(id); } @@ -19184,7 +19029,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 if (this.level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) { raid.stop(); -@@ -62,14 +76,17 @@ public class Raids extends SavedData { +@@ -71,14 +85,17 @@ public class Raids extends SavedData { } } @@ -19205,7 +19050,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 return raider != null && raid != null && raid.getLevel() != null ? raider.isAlive() && raider.canJoinRaid() && raider.getNoActionTime() <= 2400 && raider.level().dimensionType() == raid.getLevel().dimensionType() : false; } -@@ -82,7 +99,7 @@ public class Raids extends SavedData { +@@ -91,7 +108,7 @@ public class Raids extends SavedData { } else { DimensionType dimensionmanager = player.level().dimensionType(); @@ -19214,7 +19059,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 return null; } else { BlockPos blockposition = player.blockPosition(); -@@ -162,7 +179,7 @@ public class Raids extends SavedData { +@@ -171,7 +188,7 @@ public class Raids extends SavedData { public static Raids load(ServerLevel world, CompoundTag nbt) { Raids persistentraid = new Raids(world); @@ -19223,7 +19068,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 persistentraid.tick = nbt.getInt("Tick"); ListTag nbttaglist = nbt.getList("Raids", 10); -@@ -178,7 +195,7 @@ public class Raids extends SavedData { +@@ -187,7 +204,7 @@ public class Raids extends SavedData { @Override public CompoundTag save(CompoundTag nbt) { @@ -19232,7 +19077,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 nbt.putInt("Tick", this.tick); ListTag nbttaglist = new ListTag(); Iterator iterator = this.raidMap.values().iterator(); -@@ -200,7 +217,7 @@ public class Raids extends SavedData { +@@ -209,7 +226,7 @@ public class Raids extends SavedData { } private int getUniqueId() { @@ -19241,7 +19086,7 @@ index 41457c9f27b18fa2734a6cca297ec5186470e82f..71a5315faf800c2b42da36639b106c41 } @Nullable -@@ -211,6 +228,11 @@ public class Raids extends SavedData { +@@ -220,6 +237,11 @@ public class Raids extends SavedData { while (iterator.hasNext()) { Raid raid1 = (Raid) iterator.next(); @@ -19283,10 +19128,10 @@ index fc35cfc9d045f3e5b6a50af1d0ba83b6e322091f..c87765a28f31673d547653b293c48856 // Paper end diff --git a/src/main/java/net/minecraft/world/item/ArmorItem.java b/src/main/java/net/minecraft/world/item/ArmorItem.java -index d7a0cbde8f8c99276307502674c71463fbe7e89c..2a501b3fa8d69f627b279fd035fd2cb11d590f06 100644 +index 42d87800a328f71c5127ce5599ca4c71cc9bb1cd..4b08175b71e7f92e9bb578f9f6c2c0efb2ce898f 100644 --- a/src/main/java/net/minecraft/world/item/ArmorItem.java +++ b/src/main/java/net/minecraft/world/item/ArmorItem.java -@@ -68,7 +68,7 @@ public class ArmorItem extends Item implements Equipable { +@@ -69,7 +69,7 @@ public class ArmorItem extends Item implements Equipable { CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityliving.getBukkitEntity()); @@ -19296,10 +19141,10 @@ index d7a0cbde8f8c99276307502674c71463fbe7e89c..2a501b3fa8d69f627b279fd035fd2cb1 } diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242a6510192 100644 +index 4697df75fdee2023c41260bed211e3e3d90d2b9b..1a0618422675cbe4ab55a03c85c7bc383efa5cee 100644 --- a/src/main/java/net/minecraft/world/item/ItemStack.java +++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -352,31 +352,32 @@ public final class ItemStack { +@@ -357,31 +357,32 @@ public final class ItemStack { CompoundTag oldData = this.getTagClone(); int oldCount = this.getCount(); ServerLevel world = (ServerLevel) context.getLevel(); @@ -19341,7 +19186,7 @@ index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242 StructureGrowEvent structureEvent = null; if (treeType != null) { boolean isBonemeal = this.getItem() == Items.BONE_MEAL; -@@ -404,13 +405,13 @@ public final class ItemStack { +@@ -410,13 +411,13 @@ public final class ItemStack { SignItem.openSign = null; // SPIGOT-6758 - Reset on early return return enuminteractionresult; } @@ -19358,7 +19203,7 @@ index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242 if (blocks.size() > 1) { placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ()); } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - don't call event twice for snow buckets -@@ -421,13 +422,13 @@ public final class ItemStack { +@@ -427,13 +428,13 @@ public final class ItemStack { enuminteractionresult = InteractionResult.FAIL; // cancel placement // PAIL: Remove this when MC-99075 fixed placeEvent.getPlayer().updateInventory(); @@ -19375,7 +19220,7 @@ index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242 // Brute force all possible updates BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); -@@ -442,7 +443,7 @@ public final class ItemStack { +@@ -448,7 +449,7 @@ public final class ItemStack { this.setCount(newCount); } @@ -19384,7 +19229,7 @@ index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242 world.setBlockEntity(e.getValue()); } -@@ -529,8 +530,8 @@ public final class ItemStack { +@@ -535,8 +536,8 @@ public final class ItemStack { entityhuman.awardStat(Stats.ITEM_USED.get(item)); } } @@ -19396,7 +19241,7 @@ index 879cc823d56625867eb73bb621db6a13f40ad81c..d30156d5cb888b8cf2af9aee9b94e242 return enuminteractionresult; diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index d3c29e6bf8b3c2dd628809177dac50220a7de415..fbb4a46c0da5629d6bd0afee94e5bdc9ab619873 100644 +index c368b437597edf7e165326727ae778a69c3fcc83..efa947cbd9b5f98ceb6a782a6fd39884e2f0fa8c 100644 --- a/src/main/java/net/minecraft/world/item/MapItem.java +++ b/src/main/java/net/minecraft/world/item/MapItem.java @@ -103,6 +103,7 @@ public class MapItem extends ComplexItem { @@ -19460,10 +19305,10 @@ index d3c29e6bf8b3c2dd628809177dac50220a7de415..fbb4a46c0da5629d6bd0afee94e5bdc9 } } diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java -index c6d2f764efa9b8bec730bbe757d480e365b25ccc..af9313a3b3aaa0af4f2a2f4fb2424dc3e9140d9c 100644 +index a33395dc5a94d89b5ab273c7832813b6ff9ea3b7..310c8ebcf05cf5755db1baca8c585eb9a07c7f32 100644 --- a/src/main/java/net/minecraft/world/item/MinecartItem.java +++ b/src/main/java/net/minecraft/world/item/MinecartItem.java -@@ -67,7 +67,7 @@ public class MinecartItem extends Item { +@@ -69,7 +69,7 @@ public class MinecartItem extends Item { CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); BlockDispenseEvent event = new BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2)); @@ -19510,7 +19355,7 @@ index ceeedbd88c56c08ec8b047c9ca2f14cc581e12ad..19cb22df8eb29d1708e3da2124de3b43 this.lastOutput = Component.literal("[" + simpledateformat.format(date) + "] ").append(message); diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5a24a25a0 100644 +index aaa07fcd4b32fe0de88142ab30378327a01f1729..08884cc7d787887b470e90897838969d50dc4ad9 100644 --- a/src/main/java/net/minecraft/world/level/EntityGetter.java +++ b/src/main/java/net/minecraft/world/level/EntityGetter.java @@ -38,6 +38,12 @@ public interface EntityGetter { @@ -19526,7 +19371,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 List players(); default List getEntities(@Nullable Entity except, AABB box) { -@@ -92,7 +98,7 @@ public interface EntityGetter { +@@ -129,7 +135,7 @@ public interface EntityGetter { double d = -1.0D; Player player = null; @@ -19535,7 +19380,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 if (targetPredicate == null || targetPredicate.test(player2)) { double e = player2.distanceToSqr(x, y, z); if ((maxDistance < 0.0D || e < maxDistance * maxDistance) && (d == -1.0D || e < d)) { -@@ -113,7 +119,7 @@ public interface EntityGetter { +@@ -150,7 +156,7 @@ public interface EntityGetter { default List findNearbyBukkitPlayers(double x, double y, double z, double radius, @Nullable Predicate predicate) { com.google.common.collect.ImmutableList.Builder builder = com.google.common.collect.ImmutableList.builder(); @@ -19544,7 +19389,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 if (predicate == null || predicate.test(human)) { double distanceSquared = human.distanceToSqr(x, y, z); -@@ -140,7 +146,7 @@ public interface EntityGetter { +@@ -177,7 +183,7 @@ public interface EntityGetter { // Paper start default boolean hasNearbyAlivePlayerThatAffectsSpawning(double x, double y, double z, double range) { @@ -19553,7 +19398,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) { // combines NO_SPECTATORS and LIVING_ENTITY_STILL_ALIVE with an "affects spawning" check double distanceSqr = player.distanceToSqr(x, y, z); if (range < 0.0D || distanceSqr < range * range) { -@@ -153,7 +159,7 @@ public interface EntityGetter { +@@ -190,7 +196,7 @@ public interface EntityGetter { // Paper end default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) { @@ -19562,7 +19407,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { double d = player.distanceToSqr(x, y, z); if (range < 0.0D || d < range * range) { -@@ -167,17 +173,17 @@ public interface EntityGetter { +@@ -204,17 +210,17 @@ public interface EntityGetter { @Nullable default Player getNearestPlayer(TargetingConditions targetPredicate, LivingEntity entity) { @@ -19583,7 +19428,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 } @Nullable -@@ -208,7 +214,7 @@ public interface EntityGetter { +@@ -249,7 +255,7 @@ public interface EntityGetter { default List getNearbyPlayers(TargetingConditions targetPredicate, LivingEntity entity, AABB box) { List list = Lists.newArrayList(); @@ -19592,7 +19437,7 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 if (box.contains(player.getX(), player.getY(), player.getZ()) && targetPredicate.test(entity, player)) { list.add(player); } -@@ -234,8 +240,7 @@ public interface EntityGetter { +@@ -275,8 +281,7 @@ public interface EntityGetter { @Nullable default Player getPlayerByUUID(UUID uuid) { @@ -19603,10 +19448,10 @@ index 3b959f42d958bf0f426853aee56753d6c455fcdb..b1a6a66ed02706c1adc36dcedfa415f5 return player; } diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 8f97c9df726ac20cfce7bdddd5dd4f8c5aa76c35..e8c4815960ab144298d4352f393b9670e7004e62 100644 +index 45243249a561440512ef2a620c60b02e159c80e2..f875a15db0d437a32062c626fb7e42fdcc6cbfde 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -246,7 +246,7 @@ public class Explosion { +@@ -566,7 +566,7 @@ public class Explosion { continue; } @@ -19615,7 +19460,7 @@ index 8f97c9df726ac20cfce7bdddd5dd4f8c5aa76c35..e8c4815960ab144298d4352f393b9670 entity.lastDamageCancelled = false; if (entity instanceof EnderDragon) { -@@ -262,7 +262,7 @@ public class Explosion { +@@ -582,7 +582,7 @@ public class Explosion { entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f2 + 1.0D))); } @@ -19624,28 +19469,30 @@ index 8f97c9df726ac20cfce7bdddd5dd4f8c5aa76c35..e8c4815960ab144298d4352f393b9670 if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled continue; } -@@ -525,17 +525,10 @@ public class Explosion { - } - // Paper start - Optimize explosions - private float getBlockDensity(Vec3 vec3d, Entity entity) { -- if (!this.level.paperConfig().environment.optimizeExplosions) { -+ if (true || !this.level.paperConfig().environment.optimizeExplosions) { // Folia - region threading - return getSeenPercent(vec3d, entity); +@@ -852,17 +852,18 @@ public class Explosion { + if (!this.level.paperConfig().environment.optimizeExplosions) { + return this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions } -- CacheKey key = new CacheKey(this, entity.getBoundingBox()); ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.level.getCurrentWorldData(); // Folia - region threading + CacheKey key = new CacheKey(this, entity.getBoundingBox()); - Float blockDensity = this.level.explosionDensityCache.get(key); -- if (blockDensity == null) { -- blockDensity = getSeenPercent(vec3d, entity); ++ Float blockDensity = worldData.explosionDensityCache.get(key); // Folia - region threading + if (blockDensity == null) { + blockDensity = this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions; - this.level.explosionDensityCache.put(key, blockDensity); -- } -- -- return blockDensity; -+ return 0.0f; // Folia - region threading ++ worldData.explosionDensityCache.put(key, blockDensity); // Folia - region threading + } + + return blockDensity; } - static class CacheKey { +- static class CacheKey { ++ public static class CacheKey { // Folia - region threading - public + private final Level world; + private final double posX, posY, posZ; + private final double minX, minY, minZ; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e91408cd3 100644 +index ea8a0961190e9aafda4fed6fecd85097c141040a..fb889cea13d8f83f193a461ebd58fdcb115a5b34 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -117,10 +117,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -19718,25 +19565,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e // Paper start - fix and optimise world upgrading // copied from below -@@ -226,7 +216,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - List ret = new java.util.ArrayList<>(); - double maxRangeSquared = maxRange * maxRange; - -- for (net.minecraft.server.level.ServerPlayer player : (List)this.players()) { -+ for (net.minecraft.server.level.ServerPlayer player : (List)this.getLocalPlayers()) { // Folia - region threading - if ((maxRange < 0.0 || player.distanceToSqr(sourceX, sourceY, sourceZ) < maxRangeSquared)) { - if (predicate == null || predicate.test(player)) { - ret.add(player); -@@ -242,7 +232,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - net.minecraft.server.level.ServerPlayer closest = null; - double closestRangeSquared = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange; - -- for (net.minecraft.server.level.ServerPlayer player : (List)this.players()) { -+ for (net.minecraft.server.level.ServerPlayer player : (List)this.getLocalPlayers()) { // Folia - region threading - double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ); - if (distanceSquared < closestRangeSquared && (predicate == null || predicate.test(player))) { - closest = player; -@@ -273,6 +263,33 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -210,6 +200,33 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public abstract ResourceKey getTypeKey(); @@ -19770,7 +19599,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper -@@ -316,7 +333,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -253,7 +270,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.thread = Thread.currentThread(); this.biomeManager = new BiomeManager(this, i); this.isDebug = flag1; @@ -19779,7 +19608,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e this.registryAccess = iregistrycustom; this.damageSources = new DamageSources(iregistrycustom); // CraftBukkit start -@@ -541,8 +558,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -846,8 +863,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Nullable public final BlockState getBlockStateIfLoaded(BlockPos pos) { // CraftBukkit start - tree generation @@ -19790,7 +19619,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e if (previous != null) { return previous.getHandle(); } -@@ -604,16 +621,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -909,16 +926,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { @@ -19812,7 +19641,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e } blockstate.setFlag(flags); // Paper - update the flag also blockstate.setData(state); -@@ -630,10 +649,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -935,10 +954,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // CraftBukkit start - capture blockstates boolean captured = false; @@ -19825,7 +19654,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e captured = true; } // CraftBukkit end -@@ -643,8 +662,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -948,8 +967,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { if (iblockdata1 == null) { // CraftBukkit start - remove blockstate if failed (or the same) @@ -19836,7 +19665,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e } // CraftBukkit end return false; -@@ -681,7 +700,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -986,7 +1005,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { */ // CraftBukkit start @@ -19845,7 +19674,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e // Modularize client and physic updates // Spigot start try { -@@ -731,7 +750,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1036,7 +1055,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam CraftWorld world = ((ServerLevel) this).getWorld(); boolean cancelledUpdates = false; // Paper @@ -19854,7 +19683,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); this.getCraftServer().getPluginManager().callEvent(event); -@@ -745,7 +764,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1050,7 +1069,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } // CraftBukkit start - SPIGOT-5710 @@ -19863,7 +19692,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); } // CraftBukkit end -@@ -824,7 +843,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1129,7 +1148,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public void neighborShapeChanged(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int flags, int maxUpdateDepth) { @@ -19872,7 +19701,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e } @Override -@@ -849,11 +868,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1154,11 +1173,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return this.getChunkSource().getLightEngine(); } @@ -19909,7 +19738,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e if (previous != null) { return previous.getHandle(); } -@@ -944,7 +986,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1249,7 +1291,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public void addBlockEntityTicker(TickingBlockEntity ticker) { @@ -19918,7 +19747,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e } protected void tickBlockEntities() { -@@ -952,11 +994,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1257,11 +1299,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { gameprofilerfiller.push("blockEntities"); timings.tileEntityPending.startTiming(); // Spigot @@ -19934,7 +19763,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e timings.tileEntityPending.stopTiming(); // Spigot timings.tileEntityTick.startTiming(); // Spigot -@@ -965,9 +1006,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1270,9 +1311,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { int tilesThisCycle = 0; var toRemove = new it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet(net.minecraft.Util.identityStrategy()); // Paper - use removeAll toRemove.add(null); @@ -19946,7 +19775,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e // Spigot start if (tickingblockentity == null) { this.getCraftServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash"); -@@ -984,19 +1024,19 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1289,19 +1329,19 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } else if (this.shouldTickBlocksAt(tickingblockentity.getPos())) { tickingblockentity.tick(); // Paper start - execute chunk tasks during tick @@ -19971,7 +19800,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e } public void guardEntityTick(Consumer tickConsumer, T entity) { -@@ -1009,7 +1049,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1314,7 +1354,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); MinecraftServer.LOGGER.error(msg, throwable); getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable))); @@ -19981,7 +19810,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e // Paper end } } -@@ -1092,9 +1133,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1407,9 +1448,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Nullable public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) { @@ -19997,7 +19826,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e return blockEntity; } // Paper end -@@ -1107,8 +1153,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1422,8 +1468,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { if (!this.isOutsideBuildHeight(blockposition)) { // CraftBukkit start @@ -20008,7 +19837,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e return; } // CraftBukkit end -@@ -1188,6 +1234,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1503,6 +1549,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { @@ -20016,7 +19845,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e this.getProfiler().incrementCounter("getEntities"); List list = Lists.newArrayList(); ((ServerLevel)this).getEntityLookup().getEntities(except, box, list, predicate); // Paper - optimise this call -@@ -1207,6 +1254,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1522,6 +1569,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public void getEntities(EntityTypeTest filter, AABB box, Predicate predicate, List result, int limit) { @@ -20024,7 +19853,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e this.getProfiler().incrementCounter("getEntities"); // Paper start - optimise this call //TODO use limit -@@ -1244,13 +1292,30 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1559,13 +1607,30 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public void disconnect() {} @@ -20057,7 +19886,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e public boolean mayInteract(Player player, BlockPos pos) { return true; -@@ -1452,8 +1517,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1767,8 +1832,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } public final BlockPos.MutableBlockPos getRandomBlockPosition(int x, int y, int z, int l, BlockPos.MutableBlockPos out) { // Paper end @@ -20067,7 +19896,7 @@ index 773bfdd3ed457a352b5329f280c0d10297d579ba..3a760887aa1469963c34886b38cdb51e out.set(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15)); // Paper - change to setValues call return out; // Paper -@@ -1484,7 +1548,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1799,7 +1863,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public long nextSubTickCount() { @@ -20136,7 +19965,7 @@ index 12eaafdbd324fa36b3f46c3b644bc8117a4123ad..c8c358a2ce567567159039ed6a1ba804 @Deprecated default boolean hasChunksAt(int minX, int minZ, int maxX, int maxZ) { diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index e85ddf92b4f6f044e2b5834a172f37d78e702ef3..a60e63dce1869c41fe4ff97901b7143e54d1a090 100644 +index 3cdddda9c0618e95288b81b975d499c8dd30c05f..ae9aa09ba41e1f0ffe071bbac503590eeaf3bf47 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -115,11 +115,7 @@ public final class NaturalSpawner { @@ -20161,34 +19990,7 @@ index e85ddf92b4f6f044e2b5834a172f37d78e702ef3..a60e63dce1869c41fe4ff97901b7143e limit = world.getWorld().getSpawnLimit(spawnCategory); } -@@ -154,37 +150,13 @@ public final class NaturalSpawner { - continue; - } - -- // Paper start - only allow spawns upto the limit per chunk and update count afterwards -- int currEntityCount = info.mobCategoryCounts.getInt(enumcreaturetype); -- int k1 = limit * info.getSpawnableChunkCount() / NaturalSpawner.MAGIC_NUMBER; -- int difference = k1 - currEntityCount; -- -- if (world.paperConfig().entities.spawning.perPlayerMobSpawns) { -- int minDiff = Integer.MAX_VALUE; -- final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet inRange = world.getChunkSource().chunkMap.playerMobDistanceMap.getObjectsInRange(chunk.getPos()); -- if (inRange != null) { -- final Object[] backingSet = inRange.getBackingSet(); -- for (int k = 0; k < backingSet.length; k++) { -- if (!(backingSet[k] instanceof final net.minecraft.server.level.ServerPlayer player)) { -- continue; -- } -- minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear(player, enumcreaturetype), minDiff); -- } -- } -- difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; -- } -- if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && difference > 0) { -- // Paper end -+ if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && info.canSpawnForCategory(enumcreaturetype, chunk.getPos(), limit)) { // Folia - region threading - revert per player mob caps - // CraftBukkit end - Objects.requireNonNull(info); +@@ -178,11 +174,7 @@ public final class NaturalSpawner { NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn; Objects.requireNonNull(info); @@ -20201,7 +20003,7 @@ index e85ddf92b4f6f044e2b5834a172f37d78e702ef3..a60e63dce1869c41fe4ff97901b7143e } } -@@ -279,11 +251,7 @@ public final class NaturalSpawner { +@@ -277,11 +269,7 @@ public final class NaturalSpawner { // Paper start PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2); @@ -20293,7 +20095,7 @@ index d40500f9a807cab0b2fb6fa9032f33f4fb74c895..824d89c2c70c64f6b37155dcc2aa0f7b } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index fdd9c61b7248e92dbcbec91cd6fe4c6310bba237..5a216545781ac5929d497834a74ec0b0b635a6b2 100644 +index d4cbff18adb62073a1dceb189043789620af6877..4ddc3484311f9c83a6f8aecb89188195ab281742 100644 --- a/src/main/java/net/minecraft/world/level/block/Block.java +++ b/src/main/java/net/minecraft/world/level/block/Block.java @@ -382,8 +382,8 @@ public class Block extends BlockBehaviour implements ItemLike { @@ -20337,10 +20139,10 @@ index 0003fb51ae3a6575575e10b4c86719f3061e2577..362aab7977f636fa8a8548a01ab333da @Override diff --git a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -index 219c87dcf065e86512f330fbeec59e55f4675083..90e56394554b2b6d5dd12fa7f1f5279dc9a38478 100644 +index 7700461b8cd0bde1bf6c0d5e4b73184bed1adc4e..479f571152ebb17315b294469658665b6a4e0c12 100644 --- a/src/main/java/net/minecraft/world/level/block/CampfireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/CampfireBlock.java -@@ -94,9 +94,9 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB +@@ -95,9 +95,9 @@ public class CampfireBlock extends BaseEntityBlock implements SimpleWaterloggedB public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper if ((Boolean) state.getValue(CampfireBlock.LIT) && entity instanceof LivingEntity && !EnchantmentHelper.hasFrostWalker((LivingEntity) entity)) { @@ -20353,7 +20155,7 @@ index 219c87dcf065e86512f330fbeec59e55f4675083..90e56394554b2b6d5dd12fa7f1f5279d super.entityInside(state, world, pos, entity); diff --git a/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java b/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java -index 81376e725151f723dad8a7b5c1a4bd597e60294e..a9876256edd5354015e83d943a83d1c0e4060d4e 100644 +index 48eb8f0c1da1fc1971563934497059b21aebf7b6..b4b31087308a1556292e9154161425d722929de2 100644 --- a/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java +++ b/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java @@ -113,7 +113,7 @@ public class DaylightDetectorBlock extends BaseEntityBlock { @@ -20366,10 +20168,10 @@ index 81376e725151f723dad8a7b5c1a4bd597e60294e..a9876256edd5354015e83d943a83d1c0 } diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -index 4720b884e1e311f44a012f1219fe648a411247b4..911dc79ea7c6343273ecfe8fa049c115a4950654 100644 +index 9b1e51c1d95da885c80c6d05000d83436b7bcfb4..5ff51a42415306907045452c9feff62afe02898e 100644 --- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java +++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -@@ -46,7 +46,7 @@ public class DispenserBlock extends BaseEntityBlock { +@@ -48,7 +48,7 @@ public class DispenserBlock extends BaseEntityBlock { object2objectopenhashmap.defaultReturnValue(new DefaultDispenseItemBehavior()); }); private static final int TRIGGER_DURATION = 4; @@ -20378,14 +20180,14 @@ index 4720b884e1e311f44a012f1219fe648a411247b4..911dc79ea7c6343273ecfe8fa049c115 public static void registerBehavior(ItemLike provider, DispenseItemBehavior behavior) { DispenserBlock.DISPENSER_REGISTRY.put(provider.asItem(), behavior); -@@ -93,7 +93,7 @@ public class DispenserBlock extends BaseEntityBlock { +@@ -99,7 +99,7 @@ public class DispenserBlock extends BaseEntityBlock { - if (idispensebehavior != DispenseItemBehavior.NOOP) { + if (idispensebehavior != DispenseItemBehavior.NOOP) { if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - BlockPreDispenseEvent is called here -- DispenserBlock.eventFired = false; // CraftBukkit - reset event status -+ DispenserBlock.eventFired.set(false); // CraftBukkit - reset event status // Folia - region threading - tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); - } +- DispenserBlock.eventFired = false; // CraftBukkit - reset event status ++ DispenserBlock.eventFired.set(Boolean.FALSE); // CraftBukkit - reset event status // Folia - region threading + tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); + } diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java index 030b38d5d5d2578d6ef482a239ef58787efa3b08..c93a125445107d97db2a647d7b57b5f871d7e97a 100644 @@ -20401,7 +20203,7 @@ index 030b38d5d5d2578d6ef482a239ef58787efa3b08..c93a125445107d97db2a647d7b57b5f8 } // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/level/block/FungusBlock.java b/src/main/java/net/minecraft/world/level/block/FungusBlock.java -index 9d0fc6b5b8d8fb31cacf7e8b346b9babf1a3e8a2..85701eba8dea71c64f92d5eaf99cb232bf2d9722 100644 +index 17e9e2efc78cfe8577dbf4e1d6096543ad8b8ac4..37b0f51eb93a331f2d3b33deb4467f65c474b92c 100644 --- a/src/main/java/net/minecraft/world/level/block/FungusBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FungusBlock.java @@ -61,9 +61,9 @@ public class FungusBlock extends BushBlock implements BonemealableBlock { @@ -20459,7 +20261,7 @@ index 1b766045687e4dcded5cbcc50b746c55b9a34e22..a8270d65c22fa979ce53ffeeeadce8d6 super.stepOn(world, pos, state, entity); diff --git a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -index 5238b23cd3bca21e2b14c9be15699b95ad267e24..4ae4f9058167937d715ff86ae842cd210bdad195 100644 +index 302c5a6401facf192677b89cc0e9190bb35b1229..63a51676162d8e658cf10f63ff91d450850a4b86 100644 --- a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java +++ b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java @@ -93,7 +93,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { @@ -20488,7 +20290,7 @@ index cd943997f11f5ea5c600fdc6db96043fb0fa713c..7039b27f74b7898e7028cbd67184c6e9 super.fallOn(world, state, pos, entity, fallDistance); } diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -index 70544dac18381ab3fa8ddfa7d276a4ef03f9b191..858f81db707a73edeec2bb4ee62e69ad2f64200c 100644 +index 2b054439b7a763d5a3fbb5dbfe197cb9a9a3525c..f695d81a646307846abb490b484f166be2993382 100644 --- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -67,7 +67,7 @@ public class RedStoneWireBlock extends Block { @@ -20607,10 +20409,10 @@ index 70544dac18381ab3fa8ddfa7d276a4ef03f9b191..858f81db707a73edeec2bb4ee62e69ad public static int getColorForPower(int powerLevel) { diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java -index da07fce0cf7c9fbdb57d2c59e431b59bf583bf50..16e46bb6205c3f7444e864c553e8072f0519746d 100644 +index c91535f6c0bbc870fad7e04b9d341783cfcbbd63..660ade166edf1750247e6a02134581de4225f338 100644 --- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java -@@ -73,10 +73,10 @@ public class RedstoneTorchBlock extends TorchBlock { +@@ -74,10 +74,10 @@ public class RedstoneTorchBlock extends TorchBlock { public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { boolean flag = this.hasNeighborSignal(world, pos, state); // Paper start @@ -20623,7 +20425,7 @@ index da07fce0cf7c9fbdb57d2c59e431b59bf583bf50..16e46bb6205c3f7444e864c553e8072f redstoneUpdateInfos.poll(); } } -@@ -157,14 +157,14 @@ public class RedstoneTorchBlock extends TorchBlock { +@@ -158,14 +158,14 @@ public class RedstoneTorchBlock extends TorchBlock { private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) { // Paper start @@ -20641,7 +20443,7 @@ index da07fce0cf7c9fbdb57d2c59e431b59bf583bf50..16e46bb6205c3f7444e864c553e8072f } int i = 0; -@@ -185,12 +185,18 @@ public class RedstoneTorchBlock extends TorchBlock { +@@ -187,12 +187,18 @@ public class RedstoneTorchBlock extends TorchBlock { public static class Toggle { @@ -20663,7 +20465,7 @@ index da07fce0cf7c9fbdb57d2c59e431b59bf583bf50..16e46bb6205c3f7444e864c553e8072f } } diff --git a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -index d5ec1e5909c03a58add7f4597b140f787600c09a..f230d39da84304fa19bd62522b175899ad6955fd 100644 +index 53ac4e618fec3fe384d8a106c521f3eace0b5b35..2724793d0e2e455f81393775adc6ddceb2319fbc 100644 --- a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java @@ -27,7 +27,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { @@ -20717,7 +20519,7 @@ index 9bbb9f8e917288bb0d11661a1399a05631ebcce0..8d57dc0aa214e14690880f9a58234fff net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos); if (cachedBlockChunk == null) { // Is this needed? diff --git a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java -index 08a11888133b97e52535cb49cad218a1b6c6ac97..9d9564d603d5b05e60dc48d85039c384157a0dad 100644 +index 34eb7ba1adb51e394bf46a6f643db3529626d9ec..c9c544f6db4a24d66e81d9ba2929a41507c5d4af 100644 --- a/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java +++ b/src/main/java/net/minecraft/world/level/block/SweetBerryBushBlock.java @@ -85,9 +85,9 @@ public class SweetBerryBushBlock extends BushBlock implements BonemealableBlock @@ -20746,10 +20548,10 @@ index 1aa0e921890d600c9274deb923da04e72b12bcc6..daca759793b4a22406fb9c75b5ac9814 BlockState iblockdata = blockEntity.getBlockState(); boolean flag = iblockdata.is(Blocks.WITHER_SKELETON_SKULL) || iblockdata.is(Blocks.WITHER_SKELETON_WALL_SKULL); diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 3b866e2c20ee7bfc981ff09b29065530de993778..7eafe5c059580bbbe0a6de8385ad0487b590b72e 100644 +index f13943db6f2fb923c52dcf9e8bf7000041d0a362..9c3a271f98e723f1d8bf3badd3fca7a19fdc6d13 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -202,7 +202,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name +@@ -211,7 +211,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name } i1 = blockEntity.levels; @@ -20875,10 +20677,10 @@ index 963a596154091b79ca139af6274aa323518ad1ad..57b11cb78270a8094f772da497ad3264 } diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec1c3c2de6 100644 +index 1d9b23c6e458caddc2c738164e6c079cd85d3ce9..97858b410769f95e4a8d8acd757216ffe06f8cf4 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -194,12 +194,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -233,12 +233,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } // Paper start - Optimize Hoppers @@ -20894,7 +20696,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec boolean foundItem = false; for (int i = 0; i < hopper.getContainerSize(); ++i) { final ItemStack item = hopper.getItem(i); -@@ -214,7 +213,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -253,7 +252,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen // We only need to fire the event once to give protection plugins a chance to cancel this event // Because nothing uses getItem, every event call should end up the same result. @@ -20903,7 +20705,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec movedItem = callPushMoveEvent(destination, movedItem, hopper); if (movedItem == null) { // cancelled origItemStack.setCount(originalItemCount); -@@ -244,13 +243,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -283,13 +282,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) { @@ -20919,7 +20721,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec movedItem = callPullMoveEvent(hopper, container, movedItem); if (movedItem == null) { // cancelled origItemStack.setCount(originalItemCount); -@@ -270,9 +270,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -309,9 +309,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount); } @@ -20931,7 +20733,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec container.setChanged(); return true; } -@@ -287,12 +287,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -326,12 +326,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @Nullable private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) { @@ -20946,7 +20748,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec } if (!result) { cooldownHopper(hopper); -@@ -308,6 +309,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -347,6 +348,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @Nullable private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) { @@ -20954,7 +20756,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec final Inventory sourceInventory = getInventory(container); final Inventory destination = getInventory(hopper); -@@ -315,7 +317,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -354,7 +356,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen final InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false); final boolean result = event.callEvent(); if (!event.calledGetItem && !event.calledSetItem) { @@ -20963,7 +20765,7 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec } if (!result) { cooldownHopper(hopper); -@@ -460,13 +462,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -517,13 +519,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } public static boolean suckInItems(Level world, Hopper hopper) { @@ -20976,26 +20778,26 @@ index b11f51762ca289d99eaa49e66e31e58595bcea4e..1eebd3969735bff3e5559ed01ab4a2ec // Paper start - optimize hoppers and remove streams - skipPullModeEventFire = skipHopperEvents; + worldData.skipPullModeEventFire = worldData.skipHopperEvents; // Folia - region threading - return !HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> { - // Logic copied from below to avoid extra getItem calls - if (!item.isEmpty() && canTakeItemFromContainer(hopper, iinventory, item, i, enumdirection)) { -@@ -647,9 +650,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + // merge container isEmpty check and move logic into one loop + if (iinventory instanceof WorldlyContainer worldlyContainer) { + for (final int slot : worldlyContainer.getSlotsForFace(enumdirection)) { +@@ -723,9 +726,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen stack = stack.split(to.getMaxStackSize()); } // Spigot end - ignoreTileUpdates = true; // Paper -+ IGNORE_TILE_UPDATES.set(true); // Paper // Folia - region threading ++ IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper // Folia - region threading to.setItem(slot, stack); - ignoreTileUpdates = false; // Paper -+ IGNORE_TILE_UPDATES.set(false); // Paper // Folia - region threading ++ IGNORE_TILE_UPDATES.set(Boolean.FALSE); // Paper // Folia - region threading stack = leftover; // Paper flag = true; } else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -index c429990e83304951ac995556d0424479f7e83c64..9b1503574f3aba2290a00f5730e65df8c936aac4 100644 +index 6c378e3485fef4e8b8906c33a45a23e6f77e9cdd..27a5da7571f48a18756004ea5e18fb355798f0a2 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -35,9 +35,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi +@@ -36,9 +36,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi } public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { @@ -21313,10 +21115,10 @@ index 28e3b73507b988f7234cbf29c4024c88180d0aef..c8facee29ee08e0975528083f89b64f0 + BlockEntity getTileEntity(); // Folia - region threading } diff --git a/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java b/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java -index 1478483c0a5e35dfe0865ba5d819822765940dbf..8d65e8954e7677423a438d3f3eea83435945653e 100644 +index a743f36f2682a6b72ffa6644782fc081d1479eb7..f5263a71d97f404c6f6dbd3354a5ed2e98bb71db 100644 --- a/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java +++ b/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java -@@ -83,51 +83,53 @@ public abstract class AbstractTreeGrower { +@@ -75,51 +75,53 @@ public abstract class AbstractTreeGrower { // CraftBukkit start protected void setTreeType(Holder> holder) { ResourceKey> worldgentreeabstract = holder.unwrapKey().get(); @@ -21390,37 +21192,7 @@ index 1478483c0a5e35dfe0865ba5d819822765940dbf..8d65e8954e7677423a438d3f3eea8343 + SaplingBlock.treeTypeRT.set(treeType); // Folia - region threading } // CraftBukkit end - // Paper start -@@ -141,17 +143,23 @@ public abstract class AbstractTreeGrower { - } - - CaptureState recordAndSetToFalse() { -- this.previousCaptureTreeGeneration = this.level.captureTreeGeneration; -- this.previousCaptureBlockStates = this.level.captureBlockStates; -- this.level.captureTreeGeneration = false; -- this.level.captureBlockStates = false; -+ // Folia start - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.level.getCurrentWorldData(); -+ this.previousCaptureTreeGeneration = worldData.captureTreeGeneration; -+ this.previousCaptureBlockStates = worldData.captureBlockStates; -+ worldData.captureTreeGeneration = false; -+ worldData.captureBlockStates = false; -+ // Folia end - region threading - return this; - } - - @Override - public void close() { -- this.level.captureTreeGeneration = this.previousCaptureTreeGeneration; -- this.level.captureBlockStates = this.previousCaptureBlockStates; -+ // Folia start - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.level.getCurrentWorldData(); -+ worldData.captureTreeGeneration = this.previousCaptureTreeGeneration; -+ worldData.captureBlockStates = this.previousCaptureBlockStates; -+ // Folia end - region threading - } - } - // Paper end + } diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java index 1ef87580574919796dbba707f44a413ee5c5781b..a595abb43853cd4c3f5886a83527c6cbe4a3e8f7 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java @@ -21479,7 +21251,7 @@ index d5c2a608e1b4c8099c96b33d9d758e968350a46d..1a4da589142c515e713d879095b105de return true; } else { diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a314569a93 100644 +index 4abec88caab4116cfa318f7b66c6b1a8346a7401..197462de762592c129cc504cac17515ebd5aa38a 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -59,6 +59,13 @@ public class LevelChunk extends ChunkAccess { @@ -21496,109 +21268,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 @Override public boolean isRemoved() { return true; -@@ -222,51 +229,15 @@ public class LevelChunk extends ChunkAccess { - } - // Paper end - // Paper start - optimise checkDespawn -- private boolean playerGeneralAreaCacheSet; -- private com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playerGeneralAreaCache; -- -- public com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getPlayerGeneralAreaCache() { -- if (!this.playerGeneralAreaCacheSet) { -- this.updateGeneralAreaCache(); -- } -- return this.playerGeneralAreaCache; -- } -- -- public void updateGeneralAreaCache() { -- this.updateGeneralAreaCache(((ServerLevel)this.level).getChunkSource().chunkMap.playerGeneralAreaMap.getObjectsInRange(this.coordinateKey)); -- } -- -- public void removeGeneralAreaCache() { -- this.playerGeneralAreaCacheSet = false; -- this.playerGeneralAreaCache = null; -- } -- -- public void updateGeneralAreaCache(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet value) { -- this.playerGeneralAreaCacheSet = true; -- this.playerGeneralAreaCache = value; -- } -- -+ // Folia - region threading - public net.minecraft.server.level.ServerPlayer findNearestPlayer(double sourceX, double sourceY, double sourceZ, - double maxRange, java.util.function.Predicate predicate) { -- if (!this.playerGeneralAreaCacheSet) { -- this.updateGeneralAreaCache(); -- } -- -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby = this.playerGeneralAreaCache; -- -- if (nearby == null) { -- return null; -- } -- -- Object[] backingSet = nearby.getBackingSet(); -+ // Folia start - region threading - double closestDistance = maxRange < 0.0 ? Double.MAX_VALUE : maxRange * maxRange; - net.minecraft.server.level.ServerPlayer closest = null; -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- Object _player = backingSet[i]; -- if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) { -- continue; -- } -- net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player; -+ java.util.List nearby = this.level.getLocalPlayers(); -+ for (int i = 0, len = nearby.size(); i < len; ++i) { -+ net.minecraft.server.level.ServerPlayer player = nearby.get(i); - - double distance = player.distanceToSqr(sourceX, sourceY, sourceZ); - if (distance < closestDistance && predicate.test(player)) { -@@ -274,31 +245,17 @@ public class LevelChunk extends ChunkAccess { - closestDistance = distance; - } - } -- - return closest; -+ // Folia end - region threading - } - - public void getNearestPlayers(double sourceX, double sourceY, double sourceZ, java.util.function.Predicate predicate, - double range, java.util.List ret) { -- if (!this.playerGeneralAreaCacheSet) { -- this.updateGeneralAreaCache(); -- } -- -- com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet nearby = this.playerGeneralAreaCache; -- -- if (nearby == null) { -- return; -- } -- -+ // Folia start - region threading - double rangeSquared = range * range; -- -- Object[] backingSet = nearby.getBackingSet(); -- for (int i = 0, len = backingSet.length; i < len; ++i) { -- Object _player = backingSet[i]; -- if (!(_player instanceof net.minecraft.server.level.ServerPlayer)) { -- continue; -- } -- net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer)_player; -+ java.util.List nearby = this.level.getLocalPlayers(); -+ for (int i = 0, len = nearby.size(); i < len; ++i) { -+ net.minecraft.server.level.ServerPlayer player = nearby.get(i); - - if (range >= 0.0) { - double distanceSquared = player.distanceToSqr(sourceX, sourceY, sourceZ); -@@ -311,6 +268,7 @@ public class LevelChunk extends ChunkAccess { - ret.add(player); - } - } -+ // Folia end - region threading - } - // Paper end - optimise checkDespawn - -@@ -507,6 +465,7 @@ public class LevelChunk extends ChunkAccess { +@@ -416,6 +423,7 @@ public class LevelChunk extends ChunkAccess { @Nullable public BlockState setBlockState(BlockPos blockposition, BlockState iblockdata, boolean flag, boolean doPlace) { @@ -21606,7 +21276,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 // CraftBukkit end int i = blockposition.getY(); LevelChunkSection chunksection = this.getSection(this.getSectionIndex(i)); -@@ -557,7 +516,7 @@ public class LevelChunk extends ChunkAccess { +@@ -466,7 +474,7 @@ public class LevelChunk extends ChunkAccess { return null; } else { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. @@ -21615,7 +21285,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 iblockdata.onPlace(this.level, blockposition, iblockdata1, flag); } -@@ -604,7 +563,7 @@ public class LevelChunk extends ChunkAccess { +@@ -513,7 +521,7 @@ public class LevelChunk extends ChunkAccess { @Nullable public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) { // CraftBukkit start @@ -21624,7 +21294,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 if (tileentity == null) { tileentity = (BlockEntity) this.blockEntities.get(pos); } -@@ -891,13 +850,13 @@ public class LevelChunk extends ChunkAccess { +@@ -800,13 +808,13 @@ public class LevelChunk extends ChunkAccess { org.bukkit.World world = this.level.getWorld(); if (world != null) { @@ -21640,7 +21310,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 } } server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); -@@ -947,7 +906,7 @@ public class LevelChunk extends ChunkAccess { +@@ -856,7 +864,7 @@ public class LevelChunk extends ChunkAccess { @Override public boolean isUnsaved() { // Paper start - add dirty system to tick lists @@ -21649,7 +21319,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 if (this.blockTicks.isDirty(gameTime) || this.fluidTicks.isDirty(gameTime)) { return true; } -@@ -1213,6 +1172,13 @@ public class LevelChunk extends ChunkAccess { +@@ -1122,6 +1130,13 @@ public class LevelChunk extends ChunkAccess { this.ticker = wrapped; } @@ -21663,7 +21333,7 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 @Override public void tick() { this.ticker.tick(); -@@ -1249,6 +1215,13 @@ public class LevelChunk extends ChunkAccess { +@@ -1158,6 +1173,13 @@ public class LevelChunk extends ChunkAccess { this.ticker = blockentityticker; } @@ -21678,10 +21348,10 @@ index 4ff0d2fc9fd76e92e64abd69f2c9e299aa08ac32..e270816f5bbdfcfeaaaf647beb2298a3 public void tick() { if (!this.blockEntity.isRemoved() && this.blockEntity.hasLevel()) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 9c6a2884c34a9f6e775103da42480cd6b8c693b3..bc938c2a4cb30f3151b600ab88ca5c4e9734f326 100644 +index 1379084a80ce25644f13736b4a5ee5fabbd9ec1f..97533c4a31ab6137072b79dc4377fd602fef9ea8 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -639,7 +639,7 @@ public class ChunkSerializer { +@@ -646,7 +646,7 @@ public class ChunkSerializer { } private static void saveTicks(ServerLevel world, CompoundTag nbt, ChunkAccess.TicksToSave tickSchedulers) { @@ -21691,7 +21361,7 @@ index 9c6a2884c34a9f6e775103da42480cd6b8c693b3..bc938c2a4cb30f3151b600ab88ca5c4e nbt.put("block_ticks", tickSchedulers.blocks().save(i, (block) -> { return BuiltInRegistries.BLOCK.getKey(block).toString(); diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index 5b333bef255d7ef61c99510837536920c6fb6e8c..0ef4ccdb0b0468ac7c2f37635723f9b57914a9c4 100644 +index c1ff2e15bc5da1a642872ac0fdcdc457e8abb063..f73552b09913b290a7c79db3d6f064ab28553f05 100644 --- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java @@ -76,7 +76,7 @@ public class EndDragonFight { @@ -21737,7 +21407,7 @@ index 5b333bef255d7ef61c99510837536920c6fb6e8c..0ef4ccdb0b0468ac7c2f37635723f9b5 return false; } -@@ -531,6 +536,11 @@ public class EndDragonFight { +@@ -536,6 +541,11 @@ public class EndDragonFight { } public void onCrystalDestroyed(EndCrystal enderCrystal, DamageSource source) { @@ -21749,7 +21419,7 @@ index 5b333bef255d7ef61c99510837536920c6fb6e8c..0ef4ccdb0b0468ac7c2f37635723f9b5 if (this.respawnStage != null && this.respawnCrystals.contains(enderCrystal)) { EndDragonFight.LOGGER.debug("Aborting respawn sequence"); this.respawnStage = null; -@@ -559,7 +569,7 @@ public class EndDragonFight { +@@ -564,7 +574,7 @@ public class EndDragonFight { public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal // Paper end @@ -21931,7 +21601,7 @@ index 42212d4533ce25d1cfcf4c58f1fc88791d546cff..fa33c8e40bad9411e1a03899d2c37080 }); } diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -index ec81be70cd6f92bbf9011395cb361f0ce54c5ad0..d50c7dd008af14fce9073666e0fd1b609f89559c 100644 +index 598dc0d3a2b9387e76d7e4e19e54c4573a24bc54..8a139bcfc9c3de5793b1b590be6cafaae01c86e1 100644 --- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java @@ -46,6 +46,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { @@ -21943,10 +21613,10 @@ index ec81be70cd6f92bbf9011395cb361f0ce54c5ad0..d50c7dd008af14fce9073666e0fd1b60 boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; ++this.count; diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -index 353e602d476beea23e591ad770227c5d6c1e97fa..6f254ee89e1f2eb2b853888e2ff1259cd1f9a6db 100644 +index f9e3a10f91b7b22604cf13d9e7ebdca460aa39ca..92fe26539027ee57b134c1cf3c0686d7182b6fea 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java +++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -@@ -10,7 +10,7 @@ import org.slf4j.Logger; +@@ -13,7 +13,7 @@ import org.slf4j.Logger; public abstract class SavedData { private static final Logger LOGGER = LogUtils.getLogger(); @@ -21955,7 +21625,7 @@ index 353e602d476beea23e591ad770227c5d6c1e97fa..6f254ee89e1f2eb2b853888e2ff1259c public abstract CompoundTag save(CompoundTag nbt); -@@ -28,6 +28,7 @@ public abstract class SavedData { +@@ -31,6 +31,7 @@ public abstract class SavedData { public void save(File file) { if (this.isDirty()) { @@ -21963,7 +21633,7 @@ index 353e602d476beea23e591ad770227c5d6c1e97fa..6f254ee89e1f2eb2b853888e2ff1259c CompoundTag compoundTag = new CompoundTag(); compoundTag.put("data", this.save(new CompoundTag())); NbtUtils.addCurrentDataVersion(compoundTag); -@@ -38,7 +39,7 @@ public abstract class SavedData { +@@ -41,7 +42,7 @@ public abstract class SavedData { LOGGER.error("Could not save data {}", this, var4); } @@ -21971,12 +21641,12 @@ index 353e602d476beea23e591ad770227c5d6c1e97fa..6f254ee89e1f2eb2b853888e2ff1259c + // Folia - make map data thread-safe - move before save, so that any changes after are not lost } } - } + diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java -index 9b2948b5150c8f039ca667a50765109721b93947..1b76e4edce628f2b25815e28cd4cb7504a83a00f 100644 +index 3eca0b1d1407770d3986e0f09c49bc86804b604e..d76df0d600d7f17ac01ce131b85ce9289989995a 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java +++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java -@@ -27,17 +27,21 @@ public class MapIndex extends SavedData { +@@ -32,17 +32,21 @@ public class MapIndex extends SavedData { @Override public CompoundTag save(CompoundTag nbt) { @@ -21999,10 +21669,10 @@ index 9b2948b5150c8f039ca667a50765109721b93947..1b76e4edce628f2b25815e28cd4cb750 } } diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a73be3fe8 100644 +index e4c4948e076cd64686dfd16ae0568fafc1437140..ba531fcd90df266d8d0c2de907fefe994949ae0c 100644 --- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -185,7 +185,7 @@ public class MapItemSavedData extends SavedData { +@@ -192,7 +192,7 @@ public class MapItemSavedData extends SavedData { } @Override @@ -22011,7 +21681,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a DataResult dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error Logger logger = MapItemSavedData.LOGGER; -@@ -242,7 +242,7 @@ public class MapItemSavedData extends SavedData { +@@ -249,7 +249,7 @@ public class MapItemSavedData extends SavedData { return nbt; } @@ -22020,7 +21690,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a MapItemSavedData worldmap = new MapItemSavedData(this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension); worldmap.bannerMarkers.putAll(this.bannerMarkers); -@@ -253,11 +253,12 @@ public class MapItemSavedData extends SavedData { +@@ -260,11 +260,12 @@ public class MapItemSavedData extends SavedData { return worldmap; } @@ -22035,7 +21705,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a if (!this.carriedByPlayers.containsKey(player)) { MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player); -@@ -366,7 +367,7 @@ public class MapItemSavedData extends SavedData { +@@ -373,7 +374,7 @@ public class MapItemSavedData extends SavedData { rotation += rotation < 0.0D ? -8.0D : 8.0D; b2 = (byte) ((int) (rotation * 16.0D / 360.0D)); if (this.dimension == Level.NETHER && world != null) { @@ -22044,7 +21714,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a b2 = (byte) (j * j * 34187121 + j * 121 >> 15 & 15); } -@@ -425,14 +426,14 @@ public class MapItemSavedData extends SavedData { +@@ -432,14 +433,14 @@ public class MapItemSavedData extends SavedData { } @Nullable @@ -22062,7 +21732,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a Iterator iterator = this.carriedBy.iterator(); while (iterator.hasNext()) { -@@ -440,15 +441,16 @@ public class MapItemSavedData extends SavedData { +@@ -447,15 +448,16 @@ public class MapItemSavedData extends SavedData { worldmap_worldmaphumantracker.markColorsDirty(x, z); } @@ -22083,7 +21753,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player); if (worldmap_worldmaphumantracker == null) { -@@ -460,7 +462,7 @@ public class MapItemSavedData extends SavedData { +@@ -467,7 +469,7 @@ public class MapItemSavedData extends SavedData { return worldmap_worldmaphumantracker; } @@ -22092,7 +21762,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a double d0 = (double) pos.getX() + 0.5D; double d1 = (double) pos.getZ() + 0.5D; int i = 1 << this.scale; -@@ -469,7 +471,7 @@ public class MapItemSavedData extends SavedData { +@@ -476,7 +478,7 @@ public class MapItemSavedData extends SavedData { boolean flag = true; if (d2 >= -63.0D && d3 >= -63.0D && d2 <= 63.0D && d3 <= 63.0D) { @@ -22101,7 +21771,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a if (mapiconbanner == null) { return false; -@@ -490,7 +492,7 @@ public class MapItemSavedData extends SavedData { +@@ -497,7 +499,7 @@ public class MapItemSavedData extends SavedData { return false; } @@ -22110,7 +21780,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a Iterator iterator = this.bannerMarkers.values().iterator(); while (iterator.hasNext()) { -@@ -512,12 +514,12 @@ public class MapItemSavedData extends SavedData { +@@ -519,12 +521,12 @@ public class MapItemSavedData extends SavedData { return this.bannerMarkers.values(); } @@ -22125,7 +21795,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a byte b1 = this.colors[x + z * 128]; if (b1 != color) { -@@ -528,12 +530,12 @@ public class MapItemSavedData extends SavedData { +@@ -535,12 +537,12 @@ public class MapItemSavedData extends SavedData { } } @@ -22140,7 +21810,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a Iterator iterator = this.decorations.values().iterator(); MapDecoration mapicon; -@@ -568,7 +570,7 @@ public class MapItemSavedData extends SavedData { +@@ -575,7 +577,7 @@ public class MapItemSavedData extends SavedData { return this.decorations.values(); } @@ -22149,7 +21819,7 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a return this.trackedDecorationCount >= iconCount; } -@@ -694,11 +696,13 @@ public class MapItemSavedData extends SavedData { +@@ -701,11 +703,13 @@ public class MapItemSavedData extends SavedData { } public void applyToMap(MapItemSavedData mapState) { @@ -22164,18 +21834,18 @@ index 50713f03c783c63f93710d986d94af544be0615a..cb5eaaa04fe9cc820b9f4f893e81ef0a } } diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -index defe31a5d3aa89a3d18b94f2ff005594e38754b3..55609e5bfb2e1d6d8d832355080f520ec7f5b7e7 100644 +index f921f55e815a4da01828e025881a7a03591c3978..844226e119a9277741972cddf340bceb59b6cda7 100644 --- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java +++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -@@ -36,6 +36,7 @@ public class DimensionDataStorage { +@@ -35,6 +35,7 @@ public class DimensionDataStorage { } - public T computeIfAbsent(Function readFunction, Supplier supplier, String id) { + public T computeIfAbsent(SavedData.Factory type, String id) { + synchronized (this.cache) { // Folia - make map data thread-safe - T savedData = this.get(readFunction, id); + T savedData = this.get(type, id); if (savedData != null) { return savedData; -@@ -44,10 +45,12 @@ public class DimensionDataStorage { +@@ -43,10 +44,12 @@ public class DimensionDataStorage { this.set(id, savedData2); return savedData2; } @@ -22183,12 +21853,12 @@ index defe31a5d3aa89a3d18b94f2ff005594e38754b3..55609e5bfb2e1d6d8d832355080f520e } @Nullable - public T get(Function readFunction, String id) { + public T get(SavedData.Factory type, String id) { + synchronized (this.cache) { // Folia - make map data thread-safe SavedData savedData = this.cache.get(id); if (savedData == null && !this.cache.containsKey(id)) { - savedData = this.readSavedData(readFunction, id); -@@ -55,6 +58,7 @@ public class DimensionDataStorage { + savedData = this.readSavedData(type.deserializer(), type.type(), id); +@@ -54,6 +57,7 @@ public class DimensionDataStorage { } return (T)savedData; @@ -22196,7 +21866,7 @@ index defe31a5d3aa89a3d18b94f2ff005594e38754b3..55609e5bfb2e1d6d8d832355080f520e } @Nullable -@@ -73,7 +77,9 @@ public class DimensionDataStorage { +@@ -72,7 +76,9 @@ public class DimensionDataStorage { } public void set(String id, SavedData state) { @@ -22205,7 +21875,7 @@ index defe31a5d3aa89a3d18b94f2ff005594e38754b3..55609e5bfb2e1d6d8d832355080f520e + } // Folia - make map data thread-safe } - public CompoundTag readTagFromDisk(String id, int dataVersion) throws IOException { + public CompoundTag readTagFromDisk(String id, DataFixTypes dataFixTypes, int currentSaveVersion) throws IOException { diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java index ac807277a6b26d140ea9873d17c7aa4fb5fe37b2..e13d8700593f1f486cfc5c96ac25894202c07b71 100644 --- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java @@ -22338,10 +22008,10 @@ index 1d7c663fa0e550bd0cfb9a4b83ccd7e2968666f0..f3df9c9b6cff85565514f990597f3fe5 LevelChunkTicks levelChunkTicks = this.allContainers.get(l); if (levelChunkTicks == null) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d21270dfcc18c 100644 +index c9fbd5b27d01e440ad858711827698b602d660bd..7d35722cbf2da92fb0fb8a6306f18472f2499595 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -307,7 +307,7 @@ public final class CraftServer implements Server { +@@ -309,7 +309,7 @@ public final class CraftServer implements Server { private final CraftPotionBrewer potionBrewer = new CraftPotionBrewer(); // Paper // Paper start - Folia region threading API @@ -22350,7 +22020,7 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler(); private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler(); -@@ -375,6 +375,12 @@ public final class CraftServer implements Server { +@@ -377,6 +377,12 @@ public final class CraftServer implements Server { return io.papermc.paper.util.TickThread.isTickThreadFor(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandleRaw()); } // Paper end - Folia reagion threading API @@ -22363,7 +22033,7 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 static { ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); -@@ -957,6 +963,9 @@ public final class CraftServer implements Server { +@@ -961,6 +967,9 @@ public final class CraftServer implements Server { // NOTE: Should only be called from DedicatedServer.ah() public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) { @@ -22373,7 +22043,7 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 if (sender instanceof Conversable) { Conversable conversable = (Conversable) sender; -@@ -976,12 +985,44 @@ public final class CraftServer implements Server { +@@ -980,12 +989,44 @@ public final class CraftServer implements Server { } } @@ -22402,7 +22072,7 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 public boolean dispatchCommand(CommandSender sender, String commandLine) { Preconditions.checkArgument(sender != null, "sender cannot be null"); Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); - org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot + org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message + // Folia start - region threading + if ((sender instanceof Entity entity)) { @@ -22415,10 +22085,10 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 + } + // Folia end - region threading + - // Paper Start - if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) { - final CommandSender fSender = sender; -@@ -3120,7 +3161,7 @@ public final class CraftServer implements Server { + if (this.commandMap.dispatch(sender, commandLine)) { + return true; + } +@@ -3102,7 +3143,7 @@ public final class CraftServer implements Server { @Override public int getCurrentTick() { @@ -22428,7 +22098,7 @@ index 3cb207d02824af2c688e0ac9ea81860569042d65..a6ba1d101dc23b8c27a1498f3f0d2127 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb3cf61e29 100644 +index 0e670de77a7f9926e295e1dd63d909bed1a959ca..b8f10ad8687f047f2b6705d47a91831e77d6b3b4 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -183,7 +183,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -22440,7 +22110,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb } @Override -@@ -240,7 +240,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -239,7 +239,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper start - per world spawn limits for (SpawnCategory spawnCategory : SpawnCategory.values()) { if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { @@ -22449,7 +22119,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb } } // Paper end -@@ -327,6 +327,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -326,6 +326,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Chunk getChunkAt(int x, int z) { @@ -22457,7 +22127,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb warnUnsafeChunk("getting a faraway chunk", x, z); // Paper // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); -@@ -350,7 +351,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -349,7 +350,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper start private void addTicket(int x, int z) { @@ -22466,7 +22136,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb } // Paper end -@@ -369,10 +370,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -368,10 +369,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean isChunkGenerated(int x, int z) { // Paper start - Fix this method @@ -22479,7 +22149,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb } ChunkAccess chunk = world.getChunkSource().getChunkAtImmediately(x, z); if (chunk == null) { -@@ -426,7 +427,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -425,7 +426,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { } private boolean unloadChunk0(int x, int z, boolean save) { @@ -22488,7 +22158,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb if (!this.isChunkLoaded(x, z)) { return true; } -@@ -441,7 +442,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -440,7 +441,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean regenerateChunk(int x, int z) { @@ -22497,7 +22167,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper // Paper start - implement regenerateChunk method final ServerLevel serverLevel = this.world; -@@ -502,6 +503,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -501,6 +502,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean refreshChunk(int x, int z) { @@ -22505,7 +22175,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); if (playerChunk == null) return false; -@@ -537,7 +539,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -536,7 +538,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { @@ -22514,7 +22184,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb warnUnsafeChunk("loading a faraway chunk", x, z); // Paper // Paper start - Optimize this method ChunkPos chunkPos = new ChunkPos(x, z); -@@ -609,7 +611,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -608,7 +610,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; if (chunkDistanceManager.addRegionTicketAtDistance(TicketType.PLUGIN_TICKET, new ChunkPos(x, z), 2, plugin)) { // keep in-line with force loading, add at level 31 @@ -22523,7 +22193,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb return true; } -@@ -800,13 +802,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -799,13 +801,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { @@ -22544,7 +22214,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb BlockPos position = ((CraftBlockState) blockstate).getPosition(); net.minecraft.world.level.block.state.BlockState oldBlock = this.world.getBlockState(position); int flag = ((CraftBlockState) blockstate).getFlag(); -@@ -814,10 +818,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -813,10 +817,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { net.minecraft.world.level.block.state.BlockState newBlock = this.world.getBlockState(position); this.world.notifyAndUpdatePhysics(position, null, oldBlock, newBlock, newBlock, flag, 512); } @@ -22557,7 +22227,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb return false; } } -@@ -851,6 +855,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -850,6 +854,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setTime(long time) { @@ -22565,7 +22235,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb long margin = (time - this.getFullTime()) % 24000; if (margin < 0) margin += 24000; this.setFullTime(this.getFullTime() + margin); -@@ -863,6 +868,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -862,6 +867,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setFullTime(long time) { @@ -22573,7 +22243,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb // Notify anyone who's listening TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - this.world.getDayTime()); this.server.getPluginManager().callEvent(event); -@@ -890,7 +896,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -889,7 +895,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public long getGameTime() { @@ -22582,7 +22252,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb } @Override -@@ -910,11 +916,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -909,11 +915,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source) { @@ -22596,7 +22266,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb return !world.explode(source != null ? ((org.bukkit.craftbukkit.entity.CraftEntity) source).getHandle() : null, loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks ? net.minecraft.world.level.Level.ExplosionInteraction.MOB : net.minecraft.world.level.Level.ExplosionInteraction.NONE).wasCanceled; } // Paper end -@@ -984,6 +992,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -983,6 +991,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { @@ -22604,7 +22274,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper // Transient load for this tick return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); -@@ -1014,6 +1023,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1013,6 +1022,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setBiome(int x, int y, int z, Holder bb) { BlockPos pos = new BlockPos(x, 0, z); @@ -22612,7 +22282,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb if (this.world.hasChunkAt(pos)) { net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos); -@@ -1289,6 +1299,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1288,6 +1298,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setStorm(boolean hasStorm) { @@ -22620,7 +22290,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1301,6 +1312,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1300,6 +1311,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setWeatherDuration(int duration) { @@ -22628,7 +22298,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.setRainTime(duration); } -@@ -1311,6 +1323,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1310,6 +1322,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setThundering(boolean thundering) { @@ -22636,7 +22306,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper this.setThunderDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1323,6 +1336,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1322,6 +1335,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setThunderDuration(int duration) { @@ -22644,7 +22314,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.setThunderTime(duration); } -@@ -1333,6 +1347,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1332,6 +1346,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setClearWeatherDuration(int duration) { @@ -22652,7 +22322,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.setClearWeatherTime(duration); } -@@ -1527,6 +1542,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1526,6 +1541,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setKeepSpawnInMemory(boolean keepLoaded) { @@ -22660,7 +22330,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb // Paper start - Configurable spawn radius if (keepLoaded == world.keepSpawnInMemory) { // do nothing, nothing has changed -@@ -1605,6 +1621,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1604,6 +1620,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setHardcore(boolean hardcore) { @@ -22668,7 +22338,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb world.serverLevelData.settings.hardcore = hardcore; } -@@ -1617,6 +1634,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1616,6 +1633,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerAnimalSpawns(int ticksPerAnimalSpawns) { @@ -22676,7 +22346,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setTicksPerSpawns(SpawnCategory.ANIMAL, ticksPerAnimalSpawns); } -@@ -1629,6 +1647,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1628,6 +1646,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { @@ -22684,7 +22354,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setTicksPerSpawns(SpawnCategory.MONSTER, ticksPerMonsterSpawns); } -@@ -1641,6 +1660,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1640,6 +1659,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { @@ -22692,7 +22362,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setTicksPerSpawns(SpawnCategory.WATER_ANIMAL, ticksPerWaterSpawns); } -@@ -1653,6 +1673,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1652,6 +1672,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterAmbientSpawns(int ticksPerWaterAmbientSpawns) { @@ -22700,7 +22370,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setTicksPerSpawns(SpawnCategory.WATER_AMBIENT, ticksPerWaterAmbientSpawns); } -@@ -1665,6 +1686,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1664,6 +1685,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterUndergroundCreatureSpawns(int ticksPerWaterUndergroundCreatureSpawns) { @@ -22708,7 +22378,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setTicksPerSpawns(SpawnCategory.WATER_UNDERGROUND_CREATURE, ticksPerWaterUndergroundCreatureSpawns); } -@@ -1677,11 +1699,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1676,11 +1698,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { @@ -22722,7 +22392,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); -@@ -1698,21 +1722,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1697,21 +1721,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { @@ -22748,7 +22418,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.server.getWorldMetadata().removeMetadata(this, metadataKey, owningPlugin); } -@@ -1725,6 +1753,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1724,6 +1752,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setMonsterSpawnLimit(int limit) { @@ -22756,7 +22426,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.MONSTER, limit); } -@@ -1737,6 +1766,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1736,6 +1765,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setAnimalSpawnLimit(int limit) { @@ -22764,7 +22434,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.ANIMAL, limit); } -@@ -1749,6 +1779,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1748,6 +1778,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterAnimalSpawnLimit(int limit) { @@ -22772,7 +22442,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.WATER_ANIMAL, limit); } -@@ -1761,6 +1792,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1760,6 +1791,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterAmbientSpawnLimit(int limit) { @@ -22780,7 +22450,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.WATER_AMBIENT, limit); } -@@ -1773,6 +1805,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1772,6 +1804,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterUndergroundCreatureSpawnLimit(int limit) { @@ -22788,7 +22458,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.WATER_UNDERGROUND_CREATURE, limit); } -@@ -1785,6 +1818,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1784,6 +1817,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setAmbientSpawnLimit(int limit) { @@ -22796,7 +22466,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb this.setSpawnLimit(SpawnCategory.AMBIENT, limit); } -@@ -1807,6 +1841,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1806,6 +1840,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setSpawnLimit(SpawnCategory spawnCategory, int limit) { @@ -22804,16 +22474,16 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); -@@ -1861,7 +1896,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1860,7 +1895,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; - ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(BuiltInRegistries.SOUND_EVENT.wrapAsHolder(CraftSound.getSoundEffect(sound)), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, this.getHandle().getRandom().nextLong()); + ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, this.getHandle().getRandom().nextLong()); - ChunkMap.TrackedEntity entityTracker = this.getHandle().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); + ChunkMap.TrackedEntity entityTracker = ((CraftEntity) entity).getHandle().tracker; // Folia - region threading if (entityTracker != null) { entityTracker.broadcastAndSend(packet); } -@@ -1872,7 +1907,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1871,7 +1906,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(new ResourceLocation(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, this.getHandle().getRandom().nextLong()); @@ -22822,7 +22492,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb if (entityTracker != null) { entityTracker.broadcastAndSend(packet); } -@@ -1958,6 +1993,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1957,6 +1992,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean setGameRuleValue(String rule, String value) { @@ -22830,7 +22500,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb // No null values allowed if (rule == null || value == null) return false; -@@ -2000,6 +2036,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1999,6 +2035,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean setGameRule(GameRule rule, T newValue) { @@ -22838,7 +22508,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb Preconditions.checkArgument(rule != null, "GameRule cannot be null"); Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); -@@ -2265,6 +2302,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2264,6 +2301,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { @@ -22851,7 +22521,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); } // Paper end -@@ -2397,7 +2440,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2396,7 +2439,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { // Paper start public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { warnUnsafeChunk("getting a faraway chunk async", x, z); // Paper @@ -22860,7 +22530,7 @@ index f857f490ffba2f25f7c06c5fb1a1905f0b51fbe2..2c19648e68c8d25bd295e2a37ce701bb net.minecraft.world.level.chunk.LevelChunk immediate = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); if (immediate != null) { return java.util.concurrent.CompletableFuture.completedFuture(new CraftChunk(immediate)); -@@ -2414,7 +2457,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2413,7 +2456,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { @@ -22882,10 +22552,10 @@ index a3d5e319473e2f6316b3ef8edf719296e02d85a1..55abed5fdf8dc699ade5b25b1f194941 tileentitybeehive.addOccupantWithPresetTicks(entitybee, false, random.nextInt(599)); } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04abdf780af2 100644 +index 24ba4e1fd80d8effc8e70224103d3b93d69cb2ac..0dc3f04b6e0c07d13f5da385af0d150c84d2e59c 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -79,6 +79,11 @@ public class CraftBlock implements Block { +@@ -74,6 +74,11 @@ public class CraftBlock implements Block { } public net.minecraft.world.level.block.state.BlockState getNMS() { @@ -22897,7 +22567,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab return this.world.getBlockState(position); } -@@ -155,6 +160,11 @@ public class CraftBlock implements Block { +@@ -150,6 +155,11 @@ public class CraftBlock implements Block { } private void setData(final byte data, int flag) { @@ -22909,7 +22579,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab this.world.setBlock(position, CraftMagicNumbers.getBlock(this.getType(), data), flag); } -@@ -196,6 +206,11 @@ public class CraftBlock implements Block { +@@ -191,6 +201,11 @@ public class CraftBlock implements Block { } public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) { @@ -22921,7 +22591,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab // SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes // SPIGOT-4612: faster - just clear tile -@@ -341,18 +356,33 @@ public class CraftBlock implements Block { +@@ -336,18 +351,33 @@ public class CraftBlock implements Block { @Override public Biome getBiome() { @@ -22955,7 +22625,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); } -@@ -422,6 +452,11 @@ public class CraftBlock implements Block { +@@ -395,6 +425,11 @@ public class CraftBlock implements Block { @Override public boolean isBlockFaceIndirectlyPowered(BlockFace face) { @@ -22967,7 +22637,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab int power = this.world.getMinecraftWorld().getSignal(position, CraftBlock.blockFaceToNotch(face)); Block relative = this.getRelative(face); -@@ -434,6 +469,11 @@ public class CraftBlock implements Block { +@@ -407,6 +442,11 @@ public class CraftBlock implements Block { @Override public int getBlockPower(BlockFace face) { @@ -22979,7 +22649,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab int power = 0; net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); int x = this.getX(); -@@ -520,6 +560,11 @@ public class CraftBlock implements Block { +@@ -493,6 +533,11 @@ public class CraftBlock implements Block { @Override public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dropExperience) { @@ -22991,7 +22661,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab // Paper end // Order matters here, need to drop before setting to air so skulls can get their data net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS(); -@@ -563,21 +608,27 @@ public class CraftBlock implements Block { +@@ -536,21 +581,27 @@ public class CraftBlock implements Block { @Override public boolean applyBoneMeal(BlockFace face) { @@ -23026,7 +22696,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab StructureGrowEvent structureEvent = null; if (treeType != null) { -@@ -663,6 +714,11 @@ public class CraftBlock implements Block { +@@ -637,6 +688,11 @@ public class CraftBlock implements Block { @Override public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) { @@ -23038,7 +22708,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab Preconditions.checkArgument(start != null, "Location start cannot be null"); Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world"); start.checkFinite(); -@@ -704,6 +760,11 @@ public class CraftBlock implements Block { +@@ -678,6 +734,11 @@ public class CraftBlock implements Block { @Override public boolean canPlace(BlockData data) { @@ -23050,7 +22720,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab Preconditions.checkArgument(data != null, "BlockData cannot be null"); net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState(); net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); -@@ -738,6 +799,11 @@ public class CraftBlock implements Block { +@@ -712,6 +773,11 @@ public class CraftBlock implements Block { @Override public void tick() { @@ -23062,7 +22732,7 @@ index f3ac362b7b65a5273ff5fdad1d8065c5f654a53a..33274e865af871d0c5827681badf04ab net.minecraft.world.level.block.state.BlockState blockData = this.getNMS(); net.minecraft.server.level.ServerLevel level = this.world.getMinecraftWorld(); -@@ -746,6 +812,11 @@ public class CraftBlock implements Block { +@@ -720,6 +786,11 @@ public class CraftBlock implements Block { @Override public void randomTick() { @@ -23124,10 +22794,10 @@ index cd4ad8261e56365850068db1d83d6a8454026737..78f7e72f2912dae503c2dab7d1992b65 List offers = waitable.get(); if (offers == null) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 2dbe8b870fd39b4d22e9725912f443757ae70761..cba19dc27925b38f48182726a8ed6f3691ce87cc 100644 +index e932cfac619c30b8c7444a9fa41e0403a6eadf6a..b2e5ae982331555e6eb3569c88d6ab8c259ee9bc 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -582,6 +582,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -581,6 +581,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { @@ -23139,7 +22809,7 @@ index 2dbe8b870fd39b4d22e9725912f443757ae70761..cba19dc27925b38f48182726a8ed6f36 // Paper end Preconditions.checkArgument(location != null, "location cannot be null"); location.checkFinite(); -@@ -1277,7 +1282,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1276,7 +1281,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); @@ -23148,7 +22818,7 @@ index 2dbe8b870fd39b4d22e9725912f443757ae70761..cba19dc27925b38f48182726a8ed6f36 if (entityTracker == null) { return; -@@ -1341,30 +1346,43 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -1340,30 +1345,43 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { Preconditions.checkArgument(location != null, "location"); location.checkFinite(); Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. @@ -23213,10 +22883,10 @@ index 2dbe8b870fd39b4d22e9725912f443757ae70761..cba19dc27925b38f48182726a8ed6f36 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 4e6fea7cf11b1e29ae7c7098a6f5d06bb5f93cc2..2d9667e4af4629982d449249169bb55d2112dd26 100644 +index e188bb3ba5d2ec28421947c0b66b25eecb569bfe..be7904a09181ce00acb887a35eec92070515fc05 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -589,7 +589,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -591,7 +591,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kickPlayer(String message) { @@ -23225,7 +22895,7 @@ index 4e6fea7cf11b1e29ae7c7098a6f5d06bb5f93cc2..2d9667e4af4629982d449249169bb55d if (this.getHandle().connection == null) return; this.getHandle().connection.disconnect(message == null ? "" : message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause -@@ -1306,6 +1306,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1308,6 +1308,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { @@ -23237,7 +22907,7 @@ index 4e6fea7cf11b1e29ae7c7098a6f5d06bb5f93cc2..2d9667e4af4629982d449249169bb55d java.util.Set relativeArguments; java.util.Set allFlags; if (flags.length == 0) { -@@ -1888,7 +1893,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1890,7 +1895,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { private void unregisterEntity(Entity other) { // Paper end ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; @@ -23246,7 +22916,7 @@ index 4e6fea7cf11b1e29ae7c7098a6f5d06bb5f93cc2..2d9667e4af4629982d449249169bb55d if (entry != null) { entry.removePlayer(this.getHandle()); } -@@ -1985,7 +1990,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1987,7 +1992,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (original != null) otherPlayer.setUUID(original); // Paper - uuid override } @@ -23256,10 +22926,10 @@ index 4e6fea7cf11b1e29ae7c7098a6f5d06bb5f93cc2..2d9667e4af4629982d449249169bb55d entry.updatePlayer(this.getHandle()); } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40dde4e4b6 100644 +index 50fed722bbba5c663e4be33a179ea75dfa2dd9e9..d880f28bb1b6493d6df5d54dd0ed00171247b1f1 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -242,8 +242,8 @@ import org.bukkit.potion.PotionEffect; +@@ -244,8 +244,8 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.util.Vector; public class CraftEventFactory { @@ -23270,7 +22940,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 // helper methods private static boolean canBuild(ServerLevel world, Player player, int x, int z) { -@@ -890,7 +890,7 @@ public class CraftEventFactory { +@@ -892,7 +892,7 @@ public class CraftEventFactory { return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2); } @@ -23279,7 +22949,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) { // Suppress during worldgen -@@ -902,7 +902,7 @@ public class CraftEventFactory { +@@ -904,7 +904,7 @@ public class CraftEventFactory { CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag); state.setData(block); @@ -23288,7 +22958,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled()) { -@@ -1017,8 +1017,8 @@ public class CraftEventFactory { +@@ -1019,8 +1019,8 @@ public class CraftEventFactory { private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSource source, Map modifiers, Map> modifierFunctions, boolean cancelled) { if (source.is(DamageTypeTags.IS_EXPLOSION)) { DamageCause damageCause; @@ -23299,7 +22969,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 EntityDamageEvent event; if (damager == null) { event = new EntityDamageByBlockEvent(null, entity.getBukkitEntity(), DamageCause.BLOCK_EXPLOSION, modifiers, modifierFunctions, source.explodedBlockState); // Paper - handle block state in damage -@@ -1079,13 +1079,13 @@ public class CraftEventFactory { +@@ -1081,13 +1081,13 @@ public class CraftEventFactory { } return event; } else if (source.is(DamageTypes.LAVA)) { @@ -23317,7 +22987,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); -@@ -1093,9 +1093,9 @@ public class CraftEventFactory { +@@ -1095,9 +1095,9 @@ public class CraftEventFactory { entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; @@ -23329,7 +22999,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 if (source.is(DamageTypes.CACTUS) || source.is(DamageTypes.SWEET_BERRY_BUSH) || source.is(DamageTypes.STALAGMITE) || source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_ANVIL)) { cause = DamageCause.CONTACT; } else if (source.is(DamageTypes.HOT_FLOOR)) { -@@ -1110,9 +1110,9 @@ public class CraftEventFactory { +@@ -1112,9 +1112,9 @@ public class CraftEventFactory { EntityDamageEvent event = new EntityDamageByBlockEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions); event.setCancelled(cancelled); @@ -23341,7 +23011,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 if (!event.isCancelled()) { event.getEntity().setLastDamageCause(event); -@@ -1120,10 +1120,10 @@ public class CraftEventFactory { +@@ -1122,10 +1122,10 @@ public class CraftEventFactory { entity.lastDamageCancelled = true; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled } return event; @@ -23355,7 +23025,7 @@ index 090b1ee57ddef58ca71469ad860960f66da7d5a2..8bfb6899ee03e5aabfc4f49f14028a40 if (source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) { cause = DamageCause.FALLING_BLOCK; } else if (damager instanceof LightningStrike) { -@@ -2074,7 +2074,7 @@ public class CraftEventFactory { +@@ -2078,7 +2078,7 @@ public class CraftEventFactory { CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(to.getX(), to.getY(), to.getZ())); @@ -23377,10 +23047,10 @@ index d7ce4971d9271dbeff4adb9d852e4e7bdf60bf03..eb84a8dd97f92de4a7dd3826d9e124a4 if (!this.isAsyncScheduler && !task.isSync()) { this.asyncScheduler.handle(task, delay); diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 719e7103f7dfdc30f1cefd24a3fa572fa0ac8b1e..a4880371e3ec097b8bea8ecb74cbf3b9422e5afe 100644 +index 96f6e0554baf5915dd1f5b93f3bcfe7a13393c29..17c5ef57bed41fca97b845f1f6d1752a53a1121f 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -373,6 +373,12 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -355,6 +355,12 @@ public final class CraftMagicNumbers implements UnsafeValues { String minimumVersion = MinecraftServer.getServer().server.minimumAPI; int minimumIndex = CraftMagicNumbers.SUPPORTED_API.indexOf(minimumVersion); @@ -23394,7 +23064,7 @@ index 719e7103f7dfdc30f1cefd24a3fa572fa0ac8b1e..a4880371e3ec097b8bea8ecb74cbf3b9 int pluginIndex = CraftMagicNumbers.SUPPORTED_API.indexOf(pdf.getAPIVersion()); diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index eda7f0bb42f7269676d5d2193e1155912ede9920..7c4daa8557f1956c8b823d4764791c60957d1091 100644 +index 2f9e5a1adf9d67ffe18d95f2822ca3d2288fb27a..23ec7dd6fe49f33e9cac78fd084dc660fc5a2b2e 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -65,26 +65,27 @@ public class ActivationRange @@ -23462,21 +23132,25 @@ index eda7f0bb42f7269676d5d2193e1155912ede9920..7c4daa8557f1956c8b823d4764791c60 if ( world.spigotConfig.ignoreSpectatorActivation && player.isSpectator() ) { continue; -@@ -213,10 +215,11 @@ public class ActivationRange +@@ -212,10 +214,16 @@ public class ActivationRange + // Paper end // Paper start - java.util.function.Predicate entityPredicate = world.paperConfig().entities.markers.tick ? null : (e) -> !(e instanceof net.minecraft.world.entity.Marker); // Configurable marker ticking -- java.util.List entities = world.getEntities((Entity)null, maxBB, entityPredicate); +- java.util.List entities = world.getEntities((Entity)null, maxBB, null); + java.util.List entities = new java.util.ArrayList<>(); // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later -+ ((net.minecraft.server.level.ServerLevel)world).getEntityLookup().getEntities((Entity)null, maxBB, entities, entityPredicate); // Paper - optimise this call // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later ++ ((net.minecraft.server.level.ServerLevel)world).getEntityLookup().getEntities((Entity)null, maxBB, entities, null); // Paper - optimise this call // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later + boolean tickMarkers = world.paperConfig().entities.markers.tick; // Paper - configurable marker ticking for (int i = 0; i < entities.size(); i++) { Entity entity = entities.get(i); -- ActivationRange.activateEntity(entity); -+ if (io.papermc.paper.util.TickThread.isTickThreadFor(entity)) ActivationRange.activateEntity(entity); // Folia - region ticking - } - // Paper end - } -@@ -230,16 +233,16 @@ public class ActivationRange ++ // Folia start - region ticking ++ if (!io.papermc.paper.util.TickThread.isTickThreadFor(entity)) { ++ continue; ++ } ++ // Folia end - region ticking + // Paper start - configurable marker ticking + if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) { + continue; +@@ -235,16 +243,16 @@ public class ActivationRange */ private static void activateEntity(Entity entity) { @@ -23496,7 +23170,7 @@ index eda7f0bb42f7269676d5d2193e1155912ede9920..7c4daa8557f1956c8b823d4764791c60 } } } -@@ -262,10 +265,10 @@ public class ActivationRange +@@ -267,10 +275,10 @@ public class ActivationRange if (entity.getRemainingFireTicks() > 0) { return 2; } @@ -23509,7 +23183,7 @@ index eda7f0bb42f7269676d5d2193e1155912ede9920..7c4daa8557f1956c8b823d4764791c60 // Paper end // quick checks. if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper -@@ -388,19 +391,19 @@ public class ActivationRange +@@ -393,19 +401,19 @@ public class ActivationRange } // Paper end diff --git a/patches/server/0004-Max-pending-logins.patch b/patches/server/0004-Max-pending-logins.patch index e657330..bc0dd66 100644 --- a/patches/server/0004-Max-pending-logins.patch +++ b/patches/server/0004-Max-pending-logins.patch @@ -6,30 +6,30 @@ Subject: [PATCH] Max pending logins Should help the floodgates on launch diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 2e96377d628b3a07fb565020074d665f594f32e8..75b1877f8c3e4da3183437f327ef3376fd0a3c21 100644 +index 57649d7fd11bef6395e04c075980e4c34eeffaa8..106b06a1d8fbda3fae7229252e78b9c17793e988 100644 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -85,7 +85,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - UUID uniqueId = UUIDUtil.getOrCreatePlayerUUID(this.gameProfile); +@@ -88,7 +88,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, if (this.server.getPlayerList().pushPendingJoin(name, uniqueId, this.connection)) { - this.handleAcceptedLogin(); -- } -+ } else { --this.tick; } // Folia - max concurrent logins // Folia end - region threading - rewrite login process - } // Folia - region threading - remove delayed accept + this.verifyLoginAndFinishConnectionSetup((GameProfile) Objects.requireNonNull(this.authenticatedProfile)); +- } // Folia - region threading - rewrite login process ++ } else { --this.tick; } // Folia - region threading - rewrite login process // Folia - max concurrent logins + } + if (this.state == ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT && !this.isPlayerAlreadyInWorld((GameProfile) Objects.requireNonNull(this.authenticatedProfile))) { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 82c7235ad9f4bc4a9f6e018c9905d49790396918..1f70b0810ab992851662fe27c7522bc9eabf5f5f 100644 +index 3f3d3cfa046124197bf7ed8d7f4b651bf8a73416..3ed41fc4c73e418ea11ed11e365423e014c88715 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -180,6 +180,17 @@ public abstract class PlayerList { +@@ -173,6 +173,17 @@ public abstract class PlayerList { conflictingId = this.connectionById.get(byId); if (conflictingName == null && conflictingId == null) { + // Folia start - max concurrent login + int loggedInCount = 0; + for (Connection value : this.connectionById.values()) { -+ if (value.isPlayerConnected()) { ++ if (value.getPacketListener() instanceof ServerGamePacketListenerImpl) { + ++loggedInCount; + } + } diff --git a/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch b/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch index 097982e..3973587 100644 --- a/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch +++ b/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add chunk system throughput counters to /tps diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -index 300700477ee34bc22b31315825c0e40f61070cd5..0b78d1eb90500e0123b7281d722805dc65d551d0 100644 +index 679ed4d53269e1113035b462cf74ab16a231e22e..8a48238fac0949cfddcdd9ccf179d16befe9c4d4 100644 --- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java @@ -22,6 +22,9 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl diff --git a/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch b/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch index 7340deb..4678ec2 100644 --- a/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch +++ b/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch @@ -29,10 +29,10 @@ index 41bf71d116ffc5431586ce54abba7f8def6c1dcf..519da6886613b8460e989767b1a21e31 } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 71830b5fbeda3c7c63460c7cee05217dcc084882..fa35d2c1c8de225acd68e08f15976c92f7ab82aa 100644 +index 47061546345d0f367aa64c2d562a53509829d499..e1b6673729e71bdc929bc7b76983108a59e55891 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2821,6 +2821,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -2872,6 +2872,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) { return false; } else { @@ -40,7 +40,7 @@ index 71830b5fbeda3c7c63460c7cee05217dcc084882..fa35d2c1c8de225acd68e08f15976c92 // CraftBukkit start if (entity.getBukkitEntity() instanceof Vehicle && this.getBukkitEntity() instanceof LivingEntity) { VehicleEnterEvent event = new VehicleEnterEvent((Vehicle) entity.getBukkitEntity(), this.getBukkitEntity()); -@@ -2842,6 +2843,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -2893,6 +2894,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { if (event.isCancelled()) { return false; } @@ -48,7 +48,7 @@ index 71830b5fbeda3c7c63460c7cee05217dcc084882..fa35d2c1c8de225acd68e08f15976c92 // Spigot end if (this.isPassenger()) { this.stopRiding(); -@@ -2924,6 +2926,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -2971,6 +2973,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); } else { // CraftBukkit start @@ -56,7 +56,7 @@ index 71830b5fbeda3c7c63460c7cee05217dcc084882..fa35d2c1c8de225acd68e08f15976c92 CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle(); Entity orig = craft == null ? null : craft.getHandle(); if (this.getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) { -@@ -2951,6 +2954,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { +@@ -2998,6 +3001,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { if (event.isCancelled()) { return false; } @@ -246,10 +246,10 @@ index 56bc26f227b97e8e935a20c6393d3f2eb806b285..5cf8ea3a7dd4e8ea96ca6061aa1aaefc } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -index 00201cf495355939a4f35306b0e7b130c07e5c02..fd0e0eee97c3872cebeb66dabf895ccfa40a6392 100644 +index c13d7fd15d8614f1ced30569fd1eae732a31b800..a0979910520442b2cabd9e87b78448e40e753641 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java -@@ -25,8 +25,16 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud +@@ -26,8 +26,16 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud super(server, entity); } @@ -288,7 +288,7 @@ index dc26be80f2c1f058451c0d446165bc78a0ff8c47..774f0f90ad66a0f5f33d1008c036ff51 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java -index 9f30946c7a198e2a277b65c02fcd75570c5dbad6..8c73acf622e04a7a43b1be3bf96a5420d4caa2e0 100644 +index 96a20efc60efef4485eca9ebffed92dc195ed357..4a7ec1c1b479c68d0ec08b78e06b53255d725c08 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java @@ -142,8 +142,16 @@ public class CraftArrow extends AbstractProjectile implements AbstractArrow { @@ -456,10 +456,10 @@ index 80e571c977db5cdf43bfbfce035f37a3fa325c95..6fafba37dd7128a397ba046be7b33067 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java -index 533a339a2c7369475f1a66ae2c8bb1df04914614..d4e3baefd84a10e29ce1156608d36ecffbd7b634 100644 +index 6c9531c018be29b5794d047b50007fde1b50b494..cb2f710a48c1e42cf800f657befaac4e2b8a82ff 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftCat.java -@@ -13,8 +13,16 @@ public class CraftCat extends CraftTameableAnimal implements Cat { +@@ -15,8 +15,16 @@ public class CraftCat extends CraftTameableAnimal implements Cat { super(server, entity); } @@ -666,7 +666,7 @@ index 6ccb32786b3abe1109dcc2d083cd231b70d8c6b4..c3a489167197ab6392491257d9d11d80 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java -index 2fd4a8a495fd8f750fbac4fb3c571e1303fd1fab..979a26b3fc9989c0c61971fd20163f1630ddd9da 100644 +index dcfac4aebb058becafee88a334bbf1449124a2e6..4a40d50d456fbd8d736a87c887adaefdd8301257 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDisplay.java @@ -12,8 +12,16 @@ public class CraftDisplay extends CraftEntity implements Display { @@ -897,10 +897,10 @@ index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..9fc90b162aab15a9cd60b02aba563181 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index cba19dc27925b38f48182726a8ed6f3691ce87cc..ffc3c9908281a3018ca5b4e244690d459c456d83 100644 +index b2e5ae982331555e6eb3569c88d6ab8c259ee9bc..ef5d2e221463c9bae5a1275223acce7c2027fac2 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -827,7 +827,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -826,7 +826,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public UUID getUniqueId() { @@ -909,7 +909,7 @@ index cba19dc27925b38f48182726a8ed6f3691ce87cc..ffc3c9908281a3018ca5b4e244690d45 } @Override -@@ -842,6 +842,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -841,6 +841,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } public Entity getHandle() { @@ -1128,10 +1128,10 @@ index 6149067a14b950e727d3387055016a19e55c0fc6..929c817b7101973c4cc9f8f5a23f1941 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFrog.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFrog.java -index 38f16446f21761d009974930d587dafc6f700e4d..43d4027af0a1408bcef71c0f381a629c9099fe97 100644 +index 20284ba684d29c619532e076f46e11572b50d367..ad5dcae61a58dd85e01b4dcb915348acc7e74642 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFrog.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFrog.java -@@ -14,8 +14,16 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog { +@@ -16,8 +16,16 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog { super(server, entity); } @@ -1359,7 +1359,7 @@ index 8b13f6c315675bca8362be16f6511b5b7da34670..584703f2d7d14efd79568663cd833cb3 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index 7db63d9ef93902872937b69f431137336e4abc3a..5a2557570a78ef04270c2b418a63081cf3995cb7 100644 +index 017e97c1618b8ee4640b36a0ec1b07026047bfc3..546a7fd563cc0291b5e15e8f67b4c3b8fc4067af 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -291,8 +291,16 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @@ -1569,7 +1569,7 @@ index dbb435ec7a930c3b410fc4311f7eb0a4d2faa987..61f7630d2160411f35cc3ca33def30b9 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index b25f5931f836fd4d8695120f0bcb7c52deff8583..d2ab898c0f3902f5f0f9847232dac244b4095854 100644 +index fe2124694eb080cab685a1ce1f6a66e2fcdf6a17..28062755016008d0796676119fdd53d4a3947e20 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -417,6 +417,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { @@ -1806,11 +1806,11 @@ index 79b608e89d4d1f76a58868c585bb87c82e2689b1..7767a342b3d8bf9c07fbd73ad4ccacd8 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java -index 18b9b0dc70f6872a9d71c120bcd2edca531b0ac4..148d0393b093a326f76fc34c035768f4758f3f1b 100644 +index 153e4c88c168097eb4a78650e7c9c120bec202a3..d03069ef4e2b2b82d399cc5d4d6c093a9a763a88 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java @@ -55,8 +55,16 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { - return (sound != null) ? CraftSound.getBukkit(sound) : null; + return (sound != null) ? CraftSound.minecraftToBukkit(sound) : null; } + // Folia start - region threading @@ -1857,7 +1857,7 @@ index 11b23670cd80a643f266c59542a380b42b17dfbd..d3b655ab5adacd60f04f912187662c57 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java -index 1efc208dbb00b693de0c1d883e90b310cbf253e7..7c41ca305e4bb6e7aa858714763a3b6071ce2b18 100644 +index efecddaa165decac6e0958b202ad838405220627..c79bb57c3734fb313ae1a02c2c5185ba35d676f1 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java @@ -10,8 +10,16 @@ public class CraftMushroomCow extends CraftCow implements MushroomCow, io.paperm @@ -1899,10 +1899,10 @@ index b6c10507d4d62178cdf82033cc379d66d763aa9b..e0cc8454d7c2e6f3ae1805c686f3ee25 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -index 7f4b7ce6b85b4774f58be2c9afd4230a821dd9cc..1f1b4a7b7f6a74d9830402bfb03bf85335fd9825 100644 +index 3d13a79f9add2e45db7f8538ee15e0d4e37a1314..bf06c6250c98ecc10b3585a1a0a4a2385e9a789e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -@@ -51,8 +51,16 @@ public class CraftPainting extends CraftHanging implements Painting { +@@ -50,8 +50,16 @@ public class CraftPainting extends CraftHanging implements Painting { return false; } @@ -2025,7 +2025,7 @@ index fd9a841ed8a0062ece142d0cd2591786104fdda7..45653b31d2b4febe8d14bc6e1b9aa86a } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java -index f69c81e801569deae8a2536a1a57767cd2e3897f..35fab47b32808395b787d29cdfc686f5344b1bcd 100644 +index 03e74b29ebf0f9b9a0dbc6ffc872e22a22be20f0..c7411045c4901b6a66c62d68be911a4d7d1f7a9c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java @@ -75,8 +75,16 @@ public class CraftPiglin extends CraftPiglinAbstract implements Piglin, com.dest @@ -2109,10 +2109,10 @@ index 2638c341bc02f201f7ab17fdebcdbdf3a7ec05bf..0f5c2d31a2dea13a46ba81e353393633 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 2d9667e4af4629982d449249169bb55d2112dd26..8d63d9c4b2665fffcf019e69e837ba461ab017f6 100644 +index be7904a09181ce00acb887a35eec92070515fc05..27ace1119456c92b456d08a464c58d4231685f9c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -609,7 +609,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -611,7 +611,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kick(net.kyori.adventure.text.Component message, org.bukkit.event.player.PlayerKickEvent.Cause cause) { @@ -2121,7 +2121,7 @@ index 2d9667e4af4629982d449249169bb55d2112dd26..8d63d9c4b2665fffcf019e69e837ba46 final ServerGamePacketListenerImpl connection = this.getHandle().connection; if (connection != null) { connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message, cause); -@@ -2146,9 +2146,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2148,9 +2148,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this; } @@ -2139,7 +2139,7 @@ index 2d9667e4af4629982d449249169bb55d2112dd26..8d63d9c4b2665fffcf019e69e837ba46 } public void setHandle(final ServerPlayer entity) { -@@ -3148,7 +3155,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -3164,7 +3171,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { { if ( CraftPlayer.this.getHealth() <= 0 && CraftPlayer.this.isOnline() ) { @@ -2234,7 +2234,7 @@ index 1a1dfb9e5164f9962059ebf11a9c3334a1987153..38972d1aec6b32aee12972cbca2411ca } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftRaider.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftRaider.java -index c3185e189ed06e27e518d29b8577b8f694220b12..cfb231848766414297a13fea16308597546c86ce 100644 +index 763c368e299588f9a0e085a8a5e04e97e1f33428..58de24aeb98f19b2cf3fa9b0ad17e8b14bc1e475 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftRaider.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftRaider.java @@ -16,8 +16,16 @@ public abstract class CraftRaider extends CraftMonster implements Raider { @@ -2802,10 +2802,10 @@ index 04bcb1f26db12556d70e41541a5df0700d20d964..6bbb6f2720ed8fc8b54edc3922d84232 } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java -index bf1de518b8429a1543fbc863cf72a2b1e23f05d4..a491a6d96cb267c661d9af9d8c6828e05adb23b2 100644 +index 182e8e9ecb789d639b2dd7348a68e37096da53ac..3d3ce1392dc9d86965c4baf80e3d92089da5ed2c 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java -@@ -21,8 +21,16 @@ public class CraftTippedArrow extends CraftArrow implements Arrow { +@@ -22,8 +22,16 @@ public class CraftTippedArrow extends CraftArrow implements Arrow { super(server, entity); } @@ -2928,10 +2928,10 @@ index 6079581ba2eef8ac9272d0bbbf77e31f593edf0f..f89b72a75dc685c08641105c8445f4e1 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -index f29e221e5b850516c169c03bfbd2b0885d1a841b..1e201709b65b7c74d43d1fbf37bb8f968385358d 100644 +index a67b5d20b956e0bf801c9eeb9330567c21927010..6f353590ff2de58fb147bf65495018045976c1f6 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillager.java -@@ -29,8 +29,16 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { +@@ -31,8 +31,16 @@ public class CraftVillager extends CraftAbstractVillager implements Villager { super(server, entity); } @@ -2949,10 +2949,10 @@ index f29e221e5b850516c169c03bfbd2b0885d1a841b..1e201709b65b7c74d43d1fbf37bb8f96 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java -index 3c14554a6a657223441eee97258734ea05965bc7..bc2588621a80d81a757469a2b65675353da14828 100644 +index fd968881eeec6dc5bdf90decc23a2bfc619c410d..96dba371b8fe88f8e15eee5fbc152a0b85bc0511 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVillagerZombie.java -@@ -18,8 +18,16 @@ public class CraftVillagerZombie extends CraftZombie implements ZombieVillager { +@@ -14,8 +14,16 @@ public class CraftVillagerZombie extends CraftZombie implements ZombieVillager { super(server, entity); } diff --git a/patches/server/0007-Disable-mid-tick-task-execution.patch b/patches/server/0007-Disable-mid-tick-task-execution.patch index eca4948..9ea402b 100644 --- a/patches/server/0007-Disable-mid-tick-task-execution.patch +++ b/patches/server/0007-Disable-mid-tick-task-execution.patch @@ -10,10 +10,10 @@ the impact from scaling the region threads, but is not a fix to the underlying issue. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 99f1e6c72c734079dfc2c2a8b8093554e945fc6a..75eb95c330d6ab7ac1e4a69da13695bbd40f894e 100644 +index 3f283e1a5c181819b223c0f44cc5d8f274fd88a6..f9cf331202d0768a054e575c8909369920b3d59f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2874,6 +2874,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Wed, 29 Mar 2023 10:15:40 -0700 -Subject: [PATCH] Work around https://github.com/PaperMC/paperweight/issues/194 - - -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 0114f9e669d3d54a61e909ff2a706d4fe27d53bc..678bba9d636a0eb34270a2d26b5b3d0d6d900115 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -506,7 +506,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic - this.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s), cause); - } - -- @io.papermc.paper.annotation.DoNotUse // Paper -+ @Deprecated(forRemoval = true) // Folia - https://github.com/PaperMC/paperweight/issues/194 - public void disconnect(final Component reason) { - this.disconnect(PaperAdventure.asAdventure(reason), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); - } diff --git a/patches/server/0013-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch b/patches/server/0011-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch similarity index 95% rename from patches/server/0013-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch rename to patches/server/0011-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch index 3560cad..b2a87cd 100644 --- a/patches/server/0013-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch +++ b/patches/server/0011-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch @@ -9,10 +9,10 @@ add explicit block update suppression techniques, it's better than the server crashing. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 3a760887aa1469963c34886b38cdb51e91408cd3..916df0c8d263f90e04564c5f512fd5ed5eaaa6d5 100644 +index fb889cea13d8f83f193a461ebd58fdcb115a5b34..f9641a54b2d1f2eed2a48323cfa6cdd67dafdf00 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1429,7 +1429,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1744,7 +1744,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { Direction enumdirection = (Direction) iterator.next(); BlockPos blockposition1 = pos.relative(enumdirection); @@ -54,7 +54,7 @@ index 7fddb6fa8fd30ef88346a59f7867aae792f13772..b963f364b4763091c3b5d0f938eaa679 } else { RailShape blockpropertytrackposition1 = (RailShape) iblockdata.getValue(PoweredRailBlock.SHAPE); diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -index 858f81db707a73edeec2bb4ee62e69ad2f64200c..7b479d0c093732a5a8899b8f3d49a77139ef8826 100644 +index f695d81a646307846abb490b484f166be2993382..fe0ae679f3803156c253cc9caa166e7a9c6ddeed 100644 --- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -193,8 +193,9 @@ public class RedStoneWireBlock extends Block { @@ -69,7 +69,7 @@ index 858f81db707a73edeec2bb4ee62e69ad2f64200c..7b479d0c093732a5a8899b8f3d49a771 BlockState iblockdata1 = world.getBlockState(blockposition_mutableblockposition); diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -index d50c7dd008af14fce9073666e0fd1b609f89559c..5ddd8108e077bc7c1a9524854ac591c6ab99c174 100644 +index 8a139bcfc9c3de5793b1b590be6cafaae01c86e1..a61672154c4f733cdadd9ac34ca5507355d06c68 100644 --- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java @@ -119,7 +119,8 @@ public class CollectingNeighborUpdater implements NeighborUpdater { diff --git a/patches/server/0014-Block-reading-in-world-tile-entities-on-worldgen-thr.patch b/patches/server/0012-Block-reading-in-world-tile-entities-on-worldgen-thr.patch similarity index 100% rename from patches/server/0014-Block-reading-in-world-tile-entities-on-worldgen-thr.patch rename to patches/server/0012-Block-reading-in-world-tile-entities-on-worldgen-thr.patch diff --git a/patches/server/0012-Lag-compensate-block-breaking.patch b/patches/server/0012-Lag-compensate-block-breaking.patch deleted file mode 100644 index caef34c..0000000 --- a/patches/server/0012-Lag-compensate-block-breaking.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 10 Apr 2023 14:14:31 -0700 -Subject: [PATCH] Lag compensate block breaking - -Due to TPS catchup being removed, a lost tick will always -affect block breaking. - -Additionally, constant low TPS would affect block breaking -in an intrusive manner to the user when there is no need -for that to occur. - -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java -index 41db6c61de36ebb1c214423dca0ba6a0c5a95cc1..65c4e158d81ac5c5788cf4dcb379061aebd23dcd 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java -@@ -432,11 +432,25 @@ public final class RegionizedWorldData { - return this.tickData; - } - -+ // Folia start - lag compensation -+ public static final long SERVER_INIT = System.nanoTime(); -+ -+ private long lagCompensationTick; -+ -+ public long getLagCompensationTick() { -+ return this.lagCompensationTick; -+ } -+ // Folia end - lag compensation -+ - public void updateTickData() { - this.tickData = this.world.tickData; - this.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - this.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - this.skipHopperEvents = this.world.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper -+ // Folia start - lag compensation -+ // always subtract from server init so that the tick starts at zero, allowing us to cast to int without much worry -+ this.lagCompensationTick = (System.nanoTime() - SERVER_INIT) / TickRegionScheduler.TIME_BETWEEN_TICKS; -+ // Folia end - lag compensation - } - - // connections -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 82e9307e4c95edc30c9dd78cd3fefa8725140361..658effccd87cd4c940da806bcfccf47b28684d1e 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -124,7 +124,7 @@ public class ServerPlayerGameMode { - } - - public void tick() { -- ++this.gameTicks; // CraftBukkit; // Folia - region threading -+ this.gameTicks = (int)this.level.getCurrentWorldData().getLagCompensationTick(); // CraftBukkit; // Folia - region threading // Folia - lag compensation - BlockState iblockdata; - - if (this.hasDelayedDestroy) { diff --git a/patches/server/0015-Skip-worldstate-access-when-waking-players-up-during.patch b/patches/server/0013-Skip-worldstate-access-when-waking-players-up-during.patch similarity index 83% rename from patches/server/0015-Skip-worldstate-access-when-waking-players-up-during.patch rename to patches/server/0013-Skip-worldstate-access-when-waking-players-up-during.patch index 79a57b7..1852f80 100644 --- a/patches/server/0015-Skip-worldstate-access-when-waking-players-up-during.patch +++ b/patches/server/0013-Skip-worldstate-access-when-waking-players-up-during.patch @@ -9,10 +9,10 @@ data deserialization and is racey even in Vanilla. But in Folia, some accesses may throw and as such we need to fix this directly. diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 587934b8e96a3d8b8a57cda8730eb331aa63ef65..7cb6a0b99c8e51f7f767b704071473c5d8bded7d 100644 +index 914910653d90c9519062a0f1ccc9bb2f1e3ec417..500b05ce2cda7b2c0e5332e2921d55a3101fc451 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -629,7 +629,7 @@ public class ServerPlayer extends Player { +@@ -636,7 +636,7 @@ public class ServerPlayer extends Player { this.getBukkitEntity().readExtraData(nbt); // CraftBukkit if (this.isSleeping()) { @@ -22,10 +22,10 @@ index 587934b8e96a3d8b8a57cda8730eb331aa63ef65..7cb6a0b99c8e51f7f767b704071473c5 // CraftBukkit start diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 50e1390f455cf8e6da9153760f32ccb81aa20bd1..17d6349ccdbb6ac91b2705be0b855e768423c50a 100644 +index a4f2d8cc7ca428c276ad509f34c02370b13d60a3..af739286a752b50a2e207d243cd393e492729441 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -4280,6 +4280,11 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -4343,6 +4343,11 @@ public abstract class LivingEntity extends Entity implements Attackable { } }); diff --git a/patches/server/0016-Do-not-access-POI-data-for-lodestone-compass.patch b/patches/server/0014-Do-not-access-POI-data-for-lodestone-compass.patch similarity index 100% rename from patches/server/0016-Do-not-access-POI-data-for-lodestone-compass.patch rename to patches/server/0014-Do-not-access-POI-data-for-lodestone-compass.patch diff --git a/patches/server/0017-Synchronize-PaperPermissionManager.patch b/patches/server/0015-Synchronize-PaperPermissionManager.patch similarity index 100% rename from patches/server/0017-Synchronize-PaperPermissionManager.patch rename to patches/server/0015-Synchronize-PaperPermissionManager.patch diff --git a/patches/server/0016-Fix-off-region-raid-heroes.patch b/patches/server/0016-Fix-off-region-raid-heroes.patch new file mode 100644 index 0000000..cc2202b --- /dev/null +++ b/patches/server/0016-Fix-off-region-raid-heroes.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: WillQi +Date: Mon, 15 May 2023 23:45:09 -0600 +Subject: [PATCH] Fix off region raid heroes + +This patch aims to solve a potential incorrect thread call when completing a raid. +If a player is a hero of the village but proceeds to leave the region of the +raid before it's completion, it would throw an exception due to not being on the +same region thread anymore. + +diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java +index 8fc22de1aa17cd8cb52d3804533d56cbb0e6bfeb..49c0f085756889a176684922206b27ca0c660949 100644 +--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java ++++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java +@@ -410,14 +410,22 @@ public class Raid { + LivingEntity entityliving = (LivingEntity) entity; + + if (!entity.isSpectator()) { +- entityliving.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.badOmenLevel - 1, false, false, true)); ++ //entityliving.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.badOmenLevel - 1, false, false, true)); // Folia - Fix off region raid heroes - move down + if (entityliving instanceof ServerPlayer) { + ServerPlayer entityplayer = (ServerPlayer) entityliving; + +- entityplayer.awardStat(Stats.RAID_WIN); +- CriteriaTriggers.RAID_WIN.trigger(entityplayer); ++ // Folia start - Fix off region raid heroes - moved down + winners.add(entityplayer.getBukkitEntity()); // CraftBukkit + } ++ // Folia start - Fix off region raid heroes ++ entityliving.getBukkitEntity().taskScheduler.schedule((LivingEntity lv) -> { ++ lv.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.badOmenLevel - 1, false, false, true)); ++ if (lv instanceof ServerPlayer entityplayer) { ++ entityplayer.awardStat(Stats.RAID_WIN); ++ CriteriaTriggers.RAID_WIN.trigger(entityplayer); ++ } ++ }, null, 1L); ++ // Folia end - Fix off region raid heroes + } + } + } diff --git a/patches/server/0019-Remove-unused-skyLightSources.patch b/patches/server/0017-Remove-unused-skyLightSources.patch similarity index 95% rename from patches/server/0019-Remove-unused-skyLightSources.patch rename to patches/server/0017-Remove-unused-skyLightSources.patch index da1f008..22800c2 100644 --- a/patches/server/0019-Remove-unused-skyLightSources.patch +++ b/patches/server/0017-Remove-unused-skyLightSources.patch @@ -45,10 +45,10 @@ index 8b96d1b7548d354fbcabe6d1b5e9d6c3e2a5cb9d..e8fb179c5f443efd70293f31cdf00ca2 public static record TicksToSave(SerializableTickContainer blocks, SerializableTickContainer fluids) { diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index e270816f5bbdfcfeaaaf647beb2298a314569a93..94edc970f64a2c0f89eb6666de21f0f01d1c1c9d 100644 +index 197462de762592c129cc504cac17515ebd5aa38a..c474dec43f4c46421cdabc1154e22a3b269b0f11 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -306,7 +306,7 @@ public class LevelChunk extends ChunkAccess { +@@ -264,7 +264,7 @@ public class LevelChunk extends ChunkAccess { } } @@ -57,7 +57,7 @@ index e270816f5bbdfcfeaaaf647beb2298a314569a93..94edc970f64a2c0f89eb6666de21f0f0 this.setLightCorrect(protoChunk.isLightCorrect()); this.unsaved = true; this.needsDecoration = true; // CraftBukkit -@@ -498,7 +498,7 @@ public class LevelChunk extends ChunkAccess { +@@ -456,7 +456,7 @@ public class LevelChunk extends ChunkAccess { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); gameprofilerfiller.push("updateSkyLightSources"); diff --git a/patches/server/0018-Fix-off-region-raid-heroes.patch b/patches/server/0018-Fix-off-region-raid-heroes.patch deleted file mode 100644 index 186e3d3..0000000 --- a/patches/server/0018-Fix-off-region-raid-heroes.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: WillQi -Date: Mon, 15 May 2023 23:45:09 -0600 -Subject: [PATCH] Fix off region raid heroes - -This patch aims to solve a potential incorrect thread call when completing a raid. -If a player is a hero of the village but proceeds to leave the region of the -raid before it's completion, it would throw an exception due to not being on the -same region thread anymore. - -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java -index 113583d0d9de744e314bc7ee15cb8e21ec4a92f9..ddec5251b335a25cb9d8726396d90d94572dbd6b 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raid.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java -@@ -407,12 +407,25 @@ public class Raid { - if (entity instanceof LivingEntity && !entity.isSpectator()) { - LivingEntity entityliving = (LivingEntity) entity; - -- entityliving.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.badOmenLevel - 1, false, false, true)); -+ // Folia start - Fix off region raid heroes -+ entityliving.getBukkitLivingEntity().taskScheduler.schedule(task -> { -+ entityliving.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.badOmenLevel - 1, false, false, true)); -+ -+ if (entityliving instanceof ServerPlayer) { -+ ServerPlayer entityplayer = (ServerPlayer) entityliving; -+ -+ entityplayer.awardStat(Stats.RAID_WIN); -+ CriteriaTriggers.RAID_WIN.trigger(entityplayer); -+ } -+ }, null, 0); -+ // Folia end - if (entityliving instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entityliving; - -- entityplayer.awardStat(Stats.RAID_WIN); -- CriteriaTriggers.RAID_WIN.trigger(entityplayer); -+ // Folia start - Fix off region raid heroes -+ // entityplayer.awardStat(Stats.RAID_WIN); -+ // CriteriaTriggers.RAID_WIN.trigger(entityplayer); -+ // Folia end - winners.add(entityplayer.getBukkitEntity()); // CraftBukkit - } - } diff --git a/patches/server/0023-Sync-vehicle-position-to-player-position-on-player-d.patch b/patches/server/0018-Sync-vehicle-position-to-player-position-on-player-d.patch similarity index 91% rename from patches/server/0023-Sync-vehicle-position-to-player-position-on-player-d.patch rename to patches/server/0018-Sync-vehicle-position-to-player-position-on-player-d.patch index 83984de..390af21 100644 --- a/patches/server/0023-Sync-vehicle-position-to-player-position-on-player-d.patch +++ b/patches/server/0018-Sync-vehicle-position-to-player-position-on-player-d.patch @@ -7,10 +7,10 @@ This allows the player to be re-positioned before logging into the world without causing thread checks to trip on Folia. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 1f70b0810ab992851662fe27c7522bc9eabf5f5f..4f7a9a4ca030c8349a684080b44547f66ed0d2d7 100644 +index 3ed41fc4c73e418ea11ed11e365423e014c88715..7bfbcda5cf086c3c50f8cb202ceaf685a899141c 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -506,7 +506,13 @@ public abstract class PlayerList { +@@ -492,7 +492,13 @@ public abstract class PlayerList { CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle"); // CraftBukkit start ServerLevel finalWorldServer = worldserver1; diff --git a/patches/server/0020-fixup-Rewrite-chunk-system.patch b/patches/server/0020-fixup-Rewrite-chunk-system.patch deleted file mode 100644 index ad68818..0000000 --- a/patches/server/0020-fixup-Rewrite-chunk-system.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 18 Jun 2023 22:56:19 -0700 -Subject: [PATCH] fixup! Rewrite chunk system - - -diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -index 7b664f32868028758d0c6ee1eaa82efcd83661d2..c5df121d6194a97b20dc390698991b9c72dba538 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -788,20 +788,34 @@ public class RegionizedPlayerChunkLoader { - // try to push more chunk generations - final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates()))); - final int maxGensThisTick = (int)this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, maxGens); -- for (int i = 0; i < maxGensThisTick; ++i) { -- final long chunk = this.genQueue.dequeueLong(); -- final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_GENERATING); -+ int ratedGensThisTick = 0; -+ while (!this.genQueue.isEmpty()) { -+ final long chunkKey = this.genQueue.firstLong(); -+ final int chunkX = CoordinateUtils.getChunkX(chunkKey); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); -+ final ChunkAccess chunk = this.world.chunkSource.getChunkAtImmediately(chunkX, chunkZ); -+ if (chunk.getStatus() != ChunkStatus.FULL) { -+ // only rate limit actual generations -+ if ((ratedGensThisTick + 1) > maxGensThisTick) { -+ break; -+ } -+ ++ratedGensThisTick; -+ } -+ -+ this.genQueue.dequeueLong(); -+ -+ final byte prev = this.chunkTicketStage.put(chunkKey, CHUNK_TICKET_STAGE_GENERATING); - if (prev != CHUNK_TICKET_STAGE_LOADED) { - throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADED + ", not " + prev); - } - this.pushDelayedTicketOp( - ChunkHolderManager.TicketOperation.addAndRemove( -- chunk, -+ chunkKey, - REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed, - REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed - ) - ); -- this.generatingQueue.enqueue(chunk); -+ this.generatingQueue.enqueue(chunkKey); - } - - // try to pull ticking chunks diff --git a/patches/server/0021-Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/0021-Do-not-read-tile-entities-in-chunks-that-are-positio.patch deleted file mode 100644 index 9ae89de..0000000 --- a/patches/server/0021-Do-not-read-tile-entities-in-chunks-that-are-positio.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 18 Jun 2023 23:04:46 -0700 -Subject: [PATCH] Do not read tile entities in chunks that are positioned - outside of the chunk - -The tile entities are not accessible and so should not be loaded. -This can happen as a result of users moving regionfiles around, -which would cause a crash on Folia but would appear to function -fine on Paper. - -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index bc938c2a4cb30f3151b600ab88ca5c4e9734f326..035b06d00aadc67eb247efd7b25aea92ba0532a2 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -381,6 +381,13 @@ public class ChunkSerializer { - for (int k1 = 0; k1 < nbttaglist3.size(); ++k1) { - CompoundTag nbttagcompound4 = nbttaglist3.getCompound(k1); - -+ // Paper start - do not read tile entities positioned outside the chunk -+ BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound4); -+ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { -+ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); -+ continue; -+ } -+ // Paper end - do not read tile entities positioned outside the chunk - ((ChunkAccess) object1).setBlockEntityNbt(nbttagcompound4); - } - -@@ -679,10 +686,19 @@ public class ChunkSerializer { - CompoundTag nbttagcompound1 = nbttaglist1.getCompound(i); - boolean flag = nbttagcompound1.getBoolean("keepPacked"); - -+ // Paper start - do not read tile entities positioned outside the chunk -+ BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound1); // moved up -+ ChunkPos chunkPos = chunk.getPos(); -+ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { -+ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); -+ continue; -+ } -+ // Paper end - do not read tile entities positioned outside the chunk -+ - if (flag) { - chunk.setBlockEntityNbt(nbttagcompound1); - } else { -- BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound1); -+ // Paper - do not read tile entities positioned outside the chunk - move up - BlockEntity tileentity = BlockEntity.loadStatic(blockposition, chunk.getBlockState(blockposition), nbttagcompound1); - - if (tileentity != null) { diff --git a/patches/server/0022-fixup-Rewrite-chunk-system.patch b/patches/server/0022-fixup-Rewrite-chunk-system.patch deleted file mode 100644 index f0ef1b8..0000000 --- a/patches/server/0022-fixup-Rewrite-chunk-system.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 18 Jun 2023 23:25:29 -0700 -Subject: [PATCH] fixup! Rewrite chunk system - - -diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -index 26d1e1af418f980b61a57479cbc64b5bc59e0864..0cdf092d5c3f65a23e26f201768c0e2fea1ffe09 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -+++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -@@ -17,6 +17,7 @@ import net.minecraft.util.AbortableIterationConsumer; - import net.minecraft.util.Mth; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.level.ChunkPos; - import net.minecraft.world.level.entity.EntityInLevelCallback; - import net.minecraft.world.level.entity.EntityTypeTest; - import net.minecraft.world.level.entity.LevelCallback; -@@ -24,6 +25,7 @@ import net.minecraft.server.level.FullChunkStatus; - import net.minecraft.world.level.entity.LevelEntityGetter; - import net.minecraft.world.level.entity.Visibility; - import net.minecraft.world.phys.AABB; -+import net.minecraft.world.phys.Vec3; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - import org.slf4j.Logger; -@@ -319,22 +321,55 @@ public final class EntityLookup implements LevelEntityGetter { - this.getChunk(x, z).updateStatus(newStatus, this); - } - -- public void addLegacyChunkEntities(final List entities) { -- for (int i = 0, len = entities.size(); i < len; ++i) { -- this.addEntity(entities.get(i), true); -- } -+ public void addLegacyChunkEntities(final List entities, final ChunkPos forChunk) { -+ this.addEntityChunk(entities, forChunk, true); - } - -- public void addEntityChunkEntities(final List entities) { -- for (int i = 0, len = entities.size(); i < len; ++i) { -- this.addEntity(entities.get(i), true); -+ public void addEntityChunkEntities(final List entities, final ChunkPos forChunk) { -+ this.addEntityChunk(entities, forChunk, true); -+ } -+ -+ public void addWorldGenChunkEntities(final List entities, final ChunkPos forChunk) { -+ this.addEntityChunk(entities, forChunk, false); -+ } -+ -+ private void addRecursivelySafe(final Entity root, final boolean fromDisk) { -+ if (!this.addEntity(root, fromDisk)) { -+ // possible we are a passenger, and so should dismount from any valid entity in the world -+ root.stopRiding(true); -+ return; -+ } -+ for (final Entity passenger : root.getPassengers()) { -+ this.addRecursivelySafe(passenger, fromDisk); - } - } - -- public void addWorldGenChunkEntities(final List entities) { -+ private void addEntityChunk(final List entities, final ChunkPos forChunk, final boolean fromDisk) { - for (int i = 0, len = entities.size(); i < len; ++i) { -- this.addEntity(entities.get(i), false); -- } -+ final Entity entity = entities.get(i); -+ if (entity.isPassenger()) { -+ continue; -+ } -+ -+ if (!entity.chunkPosition().equals(forChunk)) { -+ LOGGER.warn("Root entity " + entity + " is outside of serialized chunk " + forChunk); -+ // can't set removed here, as we may not own the chunk position -+ // skip the entity -+ continue; -+ } -+ -+ final Vec3 rootPosition = entity.position(); -+ -+ // always adjust positions before adding passengers in case plugins access the entity, and so that -+ // they are added to the right entity chunk -+ for (final Entity passenger : entity.getIndirectPassengers()) { -+ if (!passenger.chunkPosition().equals(forChunk)) { -+ passenger.setPosRaw(rootPosition.x, rootPosition.y, rootPosition.z, true); -+ } -+ } -+ -+ this.addRecursivelySafe(entity, fromDisk); -+ } - } - - public boolean addNewEntity(final Entity entity) { -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -index 0b78d1eb90500e0123b7281d722805dc65d551d0..8a48238fac0949cfddcdd9ccf179d16befe9c4d4 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -@@ -83,7 +83,7 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl - final ServerLevel world = this.world; - final ProtoChunk protoChunk = (ProtoChunk)this.fromChunk; - chunk = new LevelChunk(this.world, protoChunk, (final LevelChunk unused) -> { -- ChunkMap.postLoadProtoChunk(world, protoChunk.getEntities()); -+ ChunkMap.postLoadProtoChunk(world, protoChunk.getEntities(), protoChunk.getPos()); // Paper - rewrite chunk system - }); - } - -diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -index f1c68d9850ece7532a8607db955eaa4fc3a4bf05..08075b8895f816420c2a940bf551dfada3c0cd9e 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java -@@ -115,7 +115,7 @@ public final class NewChunkHolder { - if (entityChunk != null) { - final List entities = EntityStorage.readEntities(this.world, entityChunk); - -- this.world.getEntityLookup().addEntityChunkEntities(entities); -+ this.world.getEntityLookup().addEntityChunkEntities(entities, new ChunkPos(this.chunkX, this.chunkZ)); - } - } - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 475edb726964f3757957474856c61ac89812c15e..6885961c7eaa07b8b25e48ca0e33e310379f6114 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -595,7 +595,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return chunkstatus1; - } - -- public static void postLoadProtoChunk(ServerLevel world, List nbt) { // Paper - public -+ public static void postLoadProtoChunk(ServerLevel world, List nbt, ChunkPos position) { // Paper - public and add chunk position parameter - if (!nbt.isEmpty()) { - // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities - world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(nbt, world).filter((entity) -> { -@@ -611,7 +611,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - checkDupeUUID(world, entity); // Paper - return !needsRemoval; -- })); -+ }), position); // Paper - rewrite chunk system - // CraftBukkit end - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index bb07ad1bb895297356b88dfc4cd17e5e93795c38..60b409e873d8f5d7975cce6e86ee2ed5525d348c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -2663,12 +2663,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - return this.entityLookup; // Paper - rewrite chunk system - } - -- public void addLegacyChunkEntities(Stream entities) { -- this.entityLookup.addLegacyChunkEntities(entities.toList()); // Paper - rewrite chunk system -+ public void addLegacyChunkEntities(Stream entities, ChunkPos forChunk) { // Paper - rewrite chunk system -+ this.entityLookup.addLegacyChunkEntities(entities.toList(), forChunk); // Paper - rewrite chunk system - } - -- public void addWorldGenChunkEntities(Stream entities) { -- this.entityLookup.addWorldGenChunkEntities(entities.toList()); // Paper - rewrite chunk system -+ public void addWorldGenChunkEntities(Stream entities, ChunkPos forChunk) { // Paper - rewrite chunk system -+ this.entityLookup.addWorldGenChunkEntities(entities.toList(), forChunk); // Paper - rewrite chunk system - } - - public void startTickingChunk(LevelChunk chunk) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -index 035b06d00aadc67eb247efd7b25aea92ba0532a2..97533c4a31ab6137072b79dc4377fd602fef9ea8 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java -@@ -678,7 +678,7 @@ public class ChunkSerializer { - - return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { - if (nbttaglist != null) { -- world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world)); -+ world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world), chunk.getPos()); // Paper - rewrite chunk system - } - - if (nbttaglist1 != null) { diff --git a/patches/server/0024-Make-loadChunksAsync-callback-thread-safe.patch b/patches/server/0024-Make-loadChunksAsync-callback-thread-safe.patch deleted file mode 100644 index 1ef9360..0000000 --- a/patches/server/0024-Make-loadChunksAsync-callback-thread-safe.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 25 Jul 2023 11:47:18 -0700 -Subject: [PATCH] Make loadChunksAsync callback thread-safe - -Need to perform synchronisation on the return list to avoid CMEs - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 60b409e873d8f5d7975cce6e86ee2ed5525d348c..cf8f93734121e5c1959959f0ba13ee4e6db31959 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -347,7 +347,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - - java.util.function.Consumer consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> { - if (chunk != null) { -+ synchronized (ret) { // Folia - region threading - make callback thread-safe TODO rebase - ret.add(chunk); -+ } // Folia - region threading - make callback thread-safe TODO rebase - chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel, holderIdentifier); - } - if (loadedChunks.incrementAndGet() == requiredChunks) { diff --git a/patches/server/0025-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch b/patches/server/0025-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch deleted file mode 100644 index 78a710b..0000000 --- a/patches/server/0025-Fix-race-condition-on-UpgradeData.BlockFixers-class-.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Tue, 8 Aug 2023 17:29:33 -0700 -Subject: [PATCH] Fix race condition on UpgradeData.BlockFixers class init - -The CHUNKY_FIXERS field is modified during the constructors -of the BlockFixers, but the code that uses CHUNKY_FIXERS does -not properly ensure that BlockFixers has been initialised before -using it, leading to a possible race condition where instances of -BlockFixers are accessed before they have initialised correctly. - -We can force the class to initialise fully before accessing the -field by calling any method on the class, and for convenience -we use values(). - -diff --git a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -index 62709ed72faf823e18ad77477eb2f5dbf9c98660..c4f9057305007ae5aea0d8655965a51080f1438a 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/UpgradeData.java -@@ -139,6 +139,7 @@ public class UpgradeData { - Fluid fluid = tick.type() == Fluids.EMPTY ? level.getFluidState(tick.pos()).getType() : tick.type(); - level.scheduleTick(tick.pos(), fluid, tick.delay(), tick.priority()); - }); -+ UpgradeData.BlockFixers.values(); // Folia - force the class init so that we don't access CHUNKY_FIXERS before all BlockFixers are initialised - CHUNKY_FIXERS.forEach((logic) -> { - logic.processChunk(level); - }); diff --git a/patches/server/0026-fixup-Optimize-Hoppers.patch b/patches/server/0026-fixup-Optimize-Hoppers.patch deleted file mode 100644 index 5c2a9fd..0000000 --- a/patches/server/0026-fixup-Optimize-Hoppers.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Sun, 27 Aug 2023 01:07:34 -0700 -Subject: [PATCH] fixup! Optimize Hoppers - - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 1eebd3969735bff3e5559ed01ab4a2ec1c3c2de6..81d8de7c80bac16d874faf990cb08f1556a46adc 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -151,6 +151,43 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - } - -+ // Paper start - optimize hoppers -+ private static final int HOPPER_EMPTY = 0; -+ private static final int HOPPER_HAS_ITEMS = 1; -+ private static final int HOPPER_IS_FULL = 2; -+ -+ private static int getFullState(final HopperBlockEntity tileEntity) { -+ tileEntity.unpackLootTable(null); -+ -+ final List hopperItems = tileEntity.getItems(); -+ -+ boolean empty = true; -+ boolean full = true; -+ -+ for (int i = 0, len = hopperItems.size(); i < len; ++i) { -+ final ItemStack stack = hopperItems.get(i); -+ if (stack.isEmpty()) { -+ full = false; -+ continue; -+ } -+ -+ if (!full) { -+ // can't be full -+ return HOPPER_HAS_ITEMS; -+ } -+ -+ empty = false; -+ -+ if (stack.getCount() != stack.getMaxStackSize()) { -+ // can't be full or empty -+ return HOPPER_HAS_ITEMS; -+ } -+ } -+ -+ return empty ? HOPPER_EMPTY : (full ? HOPPER_IS_FULL : HOPPER_HAS_ITEMS); -+ } -+ // Paper end - optimize hoppers -+ - private static boolean tryMoveItems(Level world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleansupplier) { - if (world.isClientSide) { - return false; -@@ -158,11 +195,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - if (!blockEntity.isOnCooldown() && (Boolean) state.getValue(HopperBlock.ENABLED)) { - boolean flag = false; - -- if (!blockEntity.isEmpty()) { -+ int fullState = getFullState(blockEntity); // Paper - optimize hoppers -+ -+ if (fullState != HOPPER_EMPTY) { // Paper - optimize hoppers - flag = HopperBlockEntity.ejectItems(world, pos, state, (Container) blockEntity, blockEntity); // CraftBukkit - } - -- if (!blockEntity.inventoryFull()) { -+ if (fullState != HOPPER_IS_FULL || flag) { // Paper - optimize hoppers - flag |= booleansupplier.getAsBoolean(); - } - -@@ -454,7 +493,25 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - - private static boolean isFullContainer(Container inventory, Direction direction) { -- return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams -+ // Paper start - optimize hoppers -+ if (inventory instanceof WorldlyContainer worldlyContainer) { -+ for (final int slot : worldlyContainer.getSlotsForFace(direction)) { -+ final ItemStack stack = inventory.getItem(slot); -+ if (stack.getCount() < stack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ return true; -+ } else { -+ for (int slot = 0, max = inventory.getContainerSize(); slot < max; ++slot) { -+ final ItemStack stack = inventory.getItem(slot); -+ if (stack.getCount() < stack.getMaxStackSize()) { -+ return false; -+ } -+ } -+ return true; -+ } -+ // Paper end - optimize hoppers - } - - private static boolean isEmptyContainer(Container inv, Direction facing) { -@@ -470,29 +527,43 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - // Paper start - optimize hoppers and remove streams - worldData.skipPullModeEventFire = worldData.skipHopperEvents; // Folia - region threading -- return !HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> { -- // Logic copied from below to avoid extra getItem calls -- if (!item.isEmpty() && canTakeItemFromContainer(hopper, iinventory, item, i, enumdirection)) { -- return hopperPull(world, hopper, iinventory, item, i); -- } else { -- return false; -+ // merge container isEmpty check and move logic into one loop -+ if (iinventory instanceof WorldlyContainer worldlyContainer) { -+ for (final int slot : worldlyContainer.getSlotsForFace(enumdirection)) { -+ ItemStack item = worldlyContainer.getItem(slot); -+ if (item.isEmpty() || !canTakeItemFromContainer(hopper, iinventory, item, slot, enumdirection)) { -+ continue; -+ } -+ if (hopperPull(world, hopper, iinventory, item, slot)) { -+ return true; -+ } - } -- // Paper end -- }); -+ return false; -+ } else { -+ for (int slot = 0, max = iinventory.getContainerSize(); slot < max; ++slot) { -+ ItemStack item = iinventory.getItem(slot); -+ if (item.isEmpty() || !canTakeItemFromContainer(hopper, iinventory, item, slot, enumdirection)) { -+ continue; -+ } -+ if (hopperPull(world, hopper, iinventory, item, slot)) { -+ return true; -+ } -+ } -+ return false; -+ } -+ // Paper end - } else { -- Iterator iterator = HopperBlockEntity.getItemsAtAndAbove(world, hopper).iterator(); -+ final List items = HopperBlockEntity.getItemsAtAndAbove(world, hopper); // Paper - optimize hoppers - -- ItemEntity entityitem; -- -- do { -- if (!iterator.hasNext()) { -- return false; -+ // Paper start - optimize hoppers -+ for (int i = 0, len = items.size(); i < len; ++i) { -+ if (HopperBlockEntity.addItem(hopper, items.get(i))) { -+ return true; - } -+ } - -- entityitem = (ItemEntity) iterator.next(); -- } while (!HopperBlockEntity.addItem(hopper, entityitem)); -- -- return true; -+ return false; -+ // Paper end - optimize hoppers - } - } - -@@ -550,23 +621,25 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - public static boolean addItem(Container inventory, ItemEntity itemEntity) { - boolean flag = false; - // CraftBukkit start -+ if (InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers - InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - use getInventory() to avoid snapshot creation - itemEntity.level().getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return false; - } - // CraftBukkit end -+ } // Paper - optimize hoppers - ItemStack itemstack = itemEntity.getItem().copy(); - ItemStack itemstack1 = HopperBlockEntity.addItem((Container) null, inventory, itemstack, (Direction) null); - -+ // Paper start - optimize hoppers -+ itemEntity.setItem(itemstack1); - if (itemstack1.isEmpty()) { -- flag = true; - itemEntity.discard(); -- } else { -- itemEntity.setItem(itemstack1); -+ return true; - } -- -- return flag; -+ return false; -+ // Paper end - optimize hoppers - } - - public static ItemStack addItem(@Nullable Container from, Container to, ItemStack stack, @Nullable Direction side) { -@@ -786,8 +859,8 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - } - } - -- if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper -- List list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); -+ if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !iblockdata.getBukkitMaterial().isOccluding())) { // Paper -+ List list = world.getEntitiesOfClass((Class)Container.class, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper - optimize hoppers, use getEntitiesOfClass - - if (!list.isEmpty()) { - object = (Container) list.get(world.random.nextInt(list.size()));