diff --git a/patches/unapplied/api/Add-Mob-Goal-API.patch b/patches/api/Add-Mob-Goal-API.patch similarity index 99% rename from patches/unapplied/api/Add-Mob-Goal-API.patch rename to patches/api/Add-Mob-Goal-API.patch index 7340680210..9655a7612a 100644 --- a/patches/unapplied/api/Add-Mob-Goal-API.patch +++ b/patches/api/Add-Mob-Goal-API.patch @@ -428,6 +428,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + GoalKey<Raider> OBTAIN_RAID_LEADER_BANNER = GoalKey.of(Raider.class, NamespacedKey.minecraft("obtain_raid_leader_banner")); + GoalKey<Raider> RAIDER_CELEBRATION = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_celebration")); + GoalKey<Raider> RAIDER_MOVE_THROUGH_VILLAGE = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_move_through_village")); ++ GoalKey<Creature> PARROT_WANDER = GoalKey.of(Creature.class, NamespacedKey.minecraft("parrot_wander")); + + /** + * @deprecated removed in 1.16 diff --git a/patches/unapplied/api/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/api/Add-PlayerAttackEntityCooldownResetEvent.patch similarity index 100% rename from patches/unapplied/api/Add-PlayerAttackEntityCooldownResetEvent.patch rename to patches/api/Add-PlayerAttackEntityCooldownResetEvent.patch diff --git a/patches/unapplied/api/Add-item-slot-convenience-methods.patch b/patches/api/Add-item-slot-convenience-methods.patch similarity index 100% rename from patches/unapplied/api/Add-item-slot-convenience-methods.patch rename to patches/api/Add-item-slot-convenience-methods.patch diff --git a/patches/unapplied/api/Add-villager-reputation-API.patch b/patches/api/Add-villager-reputation-API.patch similarity index 100% rename from patches/unapplied/api/Add-villager-reputation-API.patch rename to patches/api/Add-villager-reputation-API.patch diff --git a/patches/unapplied/api/Expose-game-version.patch b/patches/api/Expose-game-version.patch similarity index 100% rename from patches/unapplied/api/Expose-game-version.patch rename to patches/api/Expose-game-version.patch diff --git a/patches/unapplied/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch b/patches/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch similarity index 100% rename from patches/unapplied/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch rename to patches/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch diff --git a/patches/unapplied/api/Potential-bed-API.patch b/patches/api/Potential-bed-API.patch similarity index 100% rename from patches/unapplied/api/Potential-bed-API.patch rename to patches/api/Potential-bed-API.patch diff --git a/patches/unapplied/api/Spawn-Reason-API.patch b/patches/api/Spawn-Reason-API.patch similarity index 100% rename from patches/unapplied/api/Spawn-Reason-API.patch rename to patches/api/Spawn-Reason-API.patch diff --git a/patches/unapplied/api/Villager-Restocks-API.patch b/patches/api/Villager-Restocks-API.patch similarity index 100% rename from patches/unapplied/api/Villager-Restocks-API.patch rename to patches/api/Villager-Restocks-API.patch diff --git a/patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch similarity index 100% rename from patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch rename to patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch diff --git a/patches/unapplied/server/Add-option-for-console-having-all-permissions.patch b/patches/server/Add-option-for-console-having-all-permissions.patch similarity index 100% rename from patches/unapplied/server/Add-option-for-console-having-all-permissions.patch rename to patches/server/Add-option-for-console-having-all-permissions.patch diff --git a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch b/patches/server/Add-phantom-creative-and-insomniac-controls.patch similarity index 85% rename from patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch rename to patches/server/Add-phantom-creative-and-insomniac-controls.patch index 5a435e25ac..1be89534c3 100644 --- a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch +++ b/patches/server/Add-phantom-creative-and-insomniac-controls.patch @@ -9,27 +9,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -0,0 +0,0 @@ public class PaperWorldConfig { - lightQueueSize = getInt("light-queue-size", lightQueueSize); + } + perPlayerMobSpawns = getBoolean("per-player-mob-spawns", true); } - ++ + public boolean phantomIgnoreCreative = true; + public boolean phantomOnlyAttackInsomniacs = true; + private void phantomSettings() { + phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative); + phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs); + } -+ - public int noTickViewDistance; - private void viewDistance() { - this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1); + } diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/EntitySelector.java +++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java @@ -0,0 +0,0 @@ public final class EntitySelector { - public static final Predicate<Entity> NO_SPECTATORS = (entity) -> { return !entity.isSpectator(); }; + public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith); + public static Predicate<Player> isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper private EntitySelector() {} @@ -41,9 +39,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class Phantom extends FlyingMob implements Enemy { Player entityhuman = (Player) iterator.next(); - if (Phantom.this.canAttack((LivingEntity) entityhuman, TargetingConditions.DEFAULT)) { + if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) { + if (!level.paperConfig.phantomOnlyAttackInsomniacs || EntitySelector.isInsomniac.test(entityhuman)) // Paper - Phantom.this.setGoalTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason + Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason return true; } diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java diff --git a/patches/unapplied/server/Add-villager-reputation-API.patch b/patches/server/Add-villager-reputation-API.patch similarity index 100% rename from patches/unapplied/server/Add-villager-reputation-API.patch rename to patches/server/Add-villager-reputation-API.patch diff --git a/patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch similarity index 98% rename from patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch rename to patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index 8233943c11..eae524289c 100644 --- a/patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -32,8 +32,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 dependencies { @@ -0,0 +0,0 @@ dependencies { - - implementation("io.netty:netty-all:4.1.65.Final") // Paper + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.0") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.0") + implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation + @@ -41,13 +41,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 testImplementation("org.hamcrest:hamcrest-library:1.3") } @@ -0,0 +0,0 @@ relocation { + relocate("org.bukkit.craftbukkit" to "org.bukkit.craftbukkit.v$packageVersion") { + exclude("org.bukkit.craftbukkit.Main*") + } ++ relocate("net.fabricmc.mapping-io" to "io.papermc.dependency.mappingio") // Paper + } - relocate("org.jline:jline-terminal-jansi", "org.jline" to cb("jline")) - sequenceOf( -+ "net.fabricmc:mapping-io" to "net.fabricmc.mappingio", // Paper - "commons-codec:commons-codec" to "org.apache.commons.codec", - "commons-io:commons-io" to "org.apache.commons.io", - //"it.unimi.dsi:fastutil" to "it.unimi", // Paper - don't relocate fastutil + val generatePom = tasks.named<GenerateMavenPom>("generatePomFileForMavenPublication") @@ -0,0 +0,0 @@ tasks.shadowJar { transform(ModifiedLog4j2PluginsCacheFileTransformer::class.java) } diff --git a/patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch similarity index 100% rename from patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch rename to patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch diff --git a/patches/unapplied/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/patches/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch similarity index 100% rename from patches/unapplied/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch rename to patches/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch diff --git a/patches/unapplied/server/Ensure-safe-gateway-teleport.patch b/patches/server/Ensure-safe-gateway-teleport.patch similarity index 100% rename from patches/unapplied/server/Ensure-safe-gateway-teleport.patch rename to patches/server/Ensure-safe-gateway-teleport.patch diff --git a/patches/unapplied/server/ExperienceOrbMergeEvent.patch b/patches/server/ExperienceOrbMergeEvent.patch similarity index 100% rename from patches/unapplied/server/ExperienceOrbMergeEvent.patch rename to patches/server/ExperienceOrbMergeEvent.patch diff --git a/patches/unapplied/server/Expose-game-version.patch b/patches/server/Expose-game-version.patch similarity index 100% rename from patches/unapplied/server/Expose-game-version.patch rename to patches/server/Expose-game-version.patch diff --git a/patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch b/patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch similarity index 98% rename from patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch rename to patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch index 5d0905388f..71cb9cb2c5 100644 --- a/patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch +++ b/patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch @@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); - // Paper start - no-tick view distance + @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return Either.left(chunk); }); diff --git a/patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch similarity index 96% rename from patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch rename to patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch index 82c1ee921e..07f4670261 100644 --- a/patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch +++ b/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -0,0 +0,0 @@ public abstract class PlayerList { this.playersByUUID.put(player.getUUID(), player); - // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below + // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below + // Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks + player.supressTrackerForLogin = true; @@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 CraftPlayer bukkitPlayer = player.getBukkitEntity(); @@ -0,0 +0,0 @@ public abstract class PlayerList { - player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[] { entityplayer1})); + player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[]{entityplayer1})); } player.sentListPacket = true; + player.supressTrackerForLogin = false; // Paper diff --git a/patches/unapplied/server/Fix-PotionEffect-ignores-icon-flag.patch b/patches/server/Fix-PotionEffect-ignores-icon-flag.patch similarity index 100% rename from patches/unapplied/server/Fix-PotionEffect-ignores-icon-flag.patch rename to patches/server/Fix-PotionEffect-ignores-icon-flag.patch diff --git a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch similarity index 96% rename from patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch rename to patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch index ec34effcbe..1d9a42b1f9 100644 --- a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch +++ b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch @@ -19,7 +19,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i } else { // CraftBukkit start - Capture drops for death event if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) { @@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 entityitem.setDefaultPickUpDelay(); // CraftBukkit start -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i @Nullable public Entity teleportTo(ServerLevel worldserver, BlockPos location) { // CraftBukkit end @@ -47,7 +47,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.level instanceof ServerLevel && !this.isRemoved()) { this.level.getProfiler().push("changeDimension"); // CraftBukkit start -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i // CraftBukkit end this.level.getProfiler().popPush("reloading"); @@ -56,10 +56,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ((Mob) this).dropLeash(true, true); // Paper drop lead + } + // Paper end - Entity entity = this.getType().create((Level) worldserver); + Entity entity = this.getType().create(worldserver); if (entity != null) { -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i // CraftBukkit start - Forward the CraftEntity to the new entity this.getBukkitEntity().setHandle(entity); entity.bukkitEntity = this.getBukkitEntity(); @@ -70,7 +70,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit end } -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i } public boolean canChangeDimensions() { diff --git a/patches/unapplied/server/Fix-villager-trading-demand-MC-163962.patch b/patches/server/Fix-villager-trading-demand-MC-163962.patch similarity index 100% rename from patches/unapplied/server/Fix-villager-trading-demand-MC-163962.patch rename to patches/server/Fix-villager-trading-demand-MC-163962.patch diff --git a/patches/unapplied/server/Implement-Mob-Goal-API.patch b/patches/server/Implement-Mob-Goal-API.patch similarity index 99% rename from patches/unapplied/server/Implement-Mob-Goal-API.patch rename to patches/server/Implement-Mob-Goal-API.patch index fd8adab167..0d8e7cef0d 100644 --- a/patches/unapplied/server/Implement-Mob-Goal-API.patch +++ b/patches/server/Implement-Mob-Goal-API.patch @@ -739,14 +739,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java +++ b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java @@ -0,0 +0,0 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> { - public boolean hasCommonElements(final OptimizedSmallEnumSet<E> other) { return (other.backingSet & this.backingSet) != 0; } -+ + + public boolean hasElement(final E element) { + return (this.backingSet & (1L << element.ordinal())) != 0; + } - } ++ + public void forEach(final E[] values, final Consumer<E> action) { + long iterator = this.getBackingSet(); + int wrappedGoalSize = this.size(); diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java @@ -778,7 +780,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @@ -0,0 +0,0 @@ public abstract class Goal { - // Paper end - remove streams from pathfindergoalselector + return Mth.positiveCeilDiv(serverTicks, 2); } + // Paper start - mob goal api diff --git a/patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch b/patches/server/Load-Chunks-for-Login-Asynchronously.patch similarity index 98% rename from patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch rename to patches/server/Load-Chunks-for-Login-Asynchronously.patch index 4b5080012a..f7d37fbbac 100644 --- a/patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch +++ b/patches/server/Load-Chunks-for-Login-Asynchronously.patch @@ -94,7 +94,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper try { - ServerPlayer entityplayer1 = this.server.getPlayerList().processLogin(this.gameProfile, s); // CraftBukkit - add player reference + ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java @@ -219,7 +219,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end // CraftBukkit start - // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer})); + // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer})); @@ -0,0 +0,0 @@ public abstract class PlayerList { this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity()); // CraftBukkit end diff --git a/patches/unapplied/server/Maps-shouldn-t-load-chunks.patch b/patches/server/Maps-shouldn-t-load-chunks.patch similarity index 100% rename from patches/unapplied/server/Maps-shouldn-t-load-chunks.patch rename to patches/server/Maps-shouldn-t-load-chunks.patch diff --git a/patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch similarity index 97% rename from patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch rename to patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch index bda4803387..141f340b70 100644 --- a/patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -10,7 +10,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i bworld = server.getWorld(worldName); } diff --git a/patches/unapplied/server/Optimize-Voxel-Shape-Merging.patch b/patches/server/Optimize-Voxel-Shape-Merging.patch similarity index 100% rename from patches/unapplied/server/Optimize-Voxel-Shape-Merging.patch rename to patches/server/Optimize-Voxel-Shape-Merging.patch diff --git a/patches/unapplied/server/Optimize-brigadier-child-sorting-performance.patch b/patches/server/Optimize-brigadier-child-sorting-performance.patch similarity index 100% rename from patches/unapplied/server/Optimize-brigadier-child-sorting-performance.patch rename to patches/server/Optimize-brigadier-child-sorting-performance.patch diff --git a/patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch similarity index 93% rename from patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch rename to patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch index f7350d4804..5f4f3be4b3 100644 --- a/patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch +++ b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch @@ -9,18 +9,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -0,0 +0,0 @@ public class PaperWorldConfig { - log("Creeper lingering effect: " + disableCreeperLingeringEffect); + phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative); + phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs); } - ++ + public int expMergeMaxValue; + private void expMergeMaxValue() { + expMergeMaxValue = getInt("experience-merge-max-value", -1); + log("Experience Merge Max Value: " + expMergeMaxValue); + } -+ - public double squidMaxSpawnHeight; - private void squidMaxSpawnHeight() { - squidMaxSpawnHeight = getDouble("squid-spawn-height.maximum", 0.0D); + } diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java diff --git a/patches/unapplied/server/Potential-bed-API.patch b/patches/server/Potential-bed-API.patch similarity index 100% rename from patches/unapplied/server/Potential-bed-API.patch rename to patches/server/Potential-bed-API.patch diff --git a/patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch similarity index 98% rename from patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch rename to patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch index 5c9255d8d0..7b8a957a30 100644 --- a/patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -176,7 +176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class PortalForcer { for (int j = -1; j < 3; ++j) { for (int k = -1; k < 4; ++k) { - temp.setWithOffset((Vec3i) pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); + temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal); + // Paper start - prevent destroying unbreakable blocks + if (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits) { + if (!this.level.getBlockState(temp).isDestroyable()) { diff --git a/patches/unapplied/server/Reduce-MutableInt-allocations-from-light-engine.patch b/patches/server/Reduce-MutableInt-allocations-from-light-engine.patch similarity index 100% rename from patches/unapplied/server/Reduce-MutableInt-allocations-from-light-engine.patch rename to patches/server/Reduce-MutableInt-allocations-from-light-engine.patch diff --git a/patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch similarity index 80% rename from patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch rename to patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch index e8d8a15032..2439ae5328 100644 --- a/patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch +++ b/patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch @@ -8,23 +8,22 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void updatePlayer(ServerPlayer player) { org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (player != this.entity) { - Vec3 vec3d = player.position().subtract(this.entity.position()); // MC-155077, SPIGOT-5113 + // Paper start - remove allocation of Vec3D here -+ //Vec3D vec3d = entityplayer.getPositionVector().d(this.tracker.getPositionVector()); // MC-155077, SPIGOT-5113 ++ //Vec3 vec3d = player.position().subtract(this.entity.position()); // MC-155077, SPIGOT-5113 + double vec3d_dx = player.getX() - this.entity.getX(); -+ double vec3d_dy = player.getY() - this.entity.getY(); + double vec3d_dz = player.getZ() - this.entity.getZ(); + // Paper end - remove allocation of Vec3D here - int i = Math.min(this.getEffectiveRange(), (ChunkMap.this.viewDistance - 1) * 16); -- boolean flag = vec3d.x >= (double) (-i) && vec3d.x <= (double) i && vec3d.z >= (double) (-i) && vec3d.z <= (double) i && this.entity.broadcastToPlayer(player); -+ boolean flag = vec3d_dx >= (double) (-i) && vec3d_dx <= (double) i && vec3d_dz >= (double) (-i) && vec3d_dz <= (double) i && this.entity.broadcastToPlayer(player); // Paper - remove allocation of Vec3D here + double d0 = (double) Math.min(this.getEffectiveRange(), (ChunkMap.this.viewDistance - 1) * 16); +- double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; ++ double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper + double d2 = d0 * d0; + boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player); - // CraftBukkit start - respect vanish API - if (this.entity instanceof ServerPlayer) { diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java diff --git a/patches/unapplied/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch similarity index 100% rename from patches/unapplied/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch rename to patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch diff --git a/patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch similarity index 58% rename from patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch rename to patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch index befe2c79c2..d9d7ad5b52 100644 --- a/patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch +++ b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch @@ -13,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (l = 0; l < 128 * i; ++l) { for (i1 = 0; i1 < 128 * i; ++i1) { -- abiomebase[l * 128 * i + i1] = world.getBiome(new BlockPos((j / i - 64) * i + i1, 0, (k / i - 64) * i + l)); -+ abiomebase[l * 128 * i + i1] = world.getUncachedNoiseBiome((j / i - 64) * i + i1, 0, (k / i - 64) * i + l); // Paper - } - } +- Biome.BiomeCategory biomebase_geography = world.getBiome(new BlockPos((j / i - 64) * i + i1, 0, (k / i - 64) * i + l)).getBiomeCategory(); ++ Biome.BiomeCategory biomebase_geography = world.getUncachedNoiseBiome((j / i - 64) * i + i1, 0, (k / i - 64) * i + l).getBiomeCategory(); // Paper + aboolean[l * 128 * i + i1] = biomebase_geography == Biome.BiomeCategory.OCEAN || biomebase_geography == Biome.BiomeCategory.RIVER || biomebase_geography == Biome.BiomeCategory.SWAMP; + } diff --git a/patches/unapplied/server/Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch similarity index 100% rename from patches/unapplied/server/Validate-PickItem-Packet-and-kick-for-invalid.patch rename to patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch diff --git a/patches/unapplied/server/Villager-Restocks-API.patch b/patches/server/Villager-Restocks-API.patch similarity index 100% rename from patches/unapplied/server/Villager-Restocks-API.patch rename to patches/server/Villager-Restocks-API.patch diff --git a/patches/unapplied/server/Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/Wait-for-Async-Tasks-during-shutdown.patch similarity index 100% rename from patches/unapplied/server/Wait-for-Async-Tasks-during-shutdown.patch rename to patches/server/Wait-for-Async-Tasks-during-shutdown.patch diff --git a/patches/unapplied/server/misc-debugging-dumps.patch b/patches/server/misc-debugging-dumps.patch similarity index 97% rename from patches/unapplied/server/misc-debugging-dumps.patch rename to patches/server/misc-debugging-dumps.patch index 380b737b89..d8d1bbbf7a 100644 --- a/patches/unapplied/server/misc-debugging-dumps.patch +++ b/patches/server/misc-debugging-dumps.patch @@ -62,8 +62,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener - } } catch (Exception exception) { + ServerLoginPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); TranslatableComponent chatmessage = new TranslatableComponent("multiplayer.disconnect.invalid_player_data"); + // Paper start + if (MinecraftServer.getServer().isDebugging()) { diff --git a/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch b/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch deleted file mode 100644 index b747b0199c..0000000000 --- a/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar <aikar@aikar.co> -Date: Sat, 18 Jun 2016 23:22:12 -0400 -Subject: [PATCH] Delay Chunk Unloads based on Player Movement - -When players are moving in the world, doing things such as building or exploring, -they will commonly go back and forth in a small area. This causes a ton of chunk load -and unload activity on the edge chunks of their view distance. - -A simple back and forth movement in 6 blocks could spam a chunk to thrash a -loading and unload cycle over and over again. - -This is very wasteful. This system introduces a delay of inactivity on a chunk -before it actually unloads, which will be handled by the ticket expiry process. - -This allows servers with smaller worlds who do less long distance exploring to stop -wasting cpu cycles on saving/unloading/reloading chunks repeatedly. - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1); - } - -+ public long delayChunkUnloadsBy; -+ private void delayChunkUnloadsBy() { -+ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s")); -+ if (delayChunkUnloadsBy > 0) { -+ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds"); -+ delayChunkUnloadsBy *= 20; -+ } -+ } -+ - public boolean altItemDespawnRateEnabled; - public java.util.Map<org.bukkit.Material, Integer> altItemDespawnRateMap; - private void altItemDespawnRate() { -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - boolean removed = false; // CraftBukkit - if (arraysetsorted.remove(ticket)) { - removed = true; // CraftBukkit -+ // Paper start - delay chunk unloads for player tickets -+ long delayChunkUnloadsBy = chunkMap.level.paperConfig.delayChunkUnloadsBy; -+ if (ticket.getType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) { -+ boolean hasPlayer = false; -+ for (Ticket<?> ticket1 : arraysetsorted) { -+ if (ticket1.getType() == TicketType.PLAYER) { -+ hasPlayer = true; -+ break; -+ } -+ } -+ ChunkHolder playerChunk = chunkMap.getUpdatingChunkIfPresent(i); -+ if (!hasPlayer && playerChunk != null && playerChunk.isFullChunkReady()) { -+ Ticket<Long> delayUnload = new Ticket<Long>(TicketType.DELAY_UNLOAD, 33, i); -+ delayUnload.delayUnloadBy = delayChunkUnloadsBy; -+ delayUnload.setCreatedTick(this.ticketTickCounter); -+ arraysetsorted.remove(delayUnload); -+ // refresh ticket -+ arraysetsorted.add(delayUnload); -+ } -+ } -+ // Paper end - } - - if (arraysetsorted.isEmpty()) { -diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/Ticket.java -+++ b/src/main/java/net/minecraft/server/level/Ticket.java -@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { - private final int ticketLevel; - public final T key; - public long createdTick; -+ public long delayUnloadBy; // Paper - - protected Ticket(TicketType<T> type, int level, T argument) { - this.type = type; - this.ticketLevel = level; - this.key = argument; -+ this.delayUnloadBy = type.timeout; // Paper - } - - @Override -@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { - } - - protected boolean timedOut(long currentTick) { -- long l = this.type.timeout(); -+ long l = delayUnloadBy; // Paper - return l != 0L && currentTick - this.createdTick > l; - } - } -diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/TicketType.java -+++ b/src/main/java/net/minecraft/server/level/TicketType.java -@@ -0,0 +0,0 @@ public class TicketType<T> { - public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1); - public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit - public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit -+ public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper - - public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) { - return new TicketType<>(name, argumentComparator, 0L); diff --git a/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch b/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch deleted file mode 100644 index e4009f1419..0000000000 --- a/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar <aikar@aikar.co> -Date: Sat, 23 May 2020 01:31:06 -0400 -Subject: [PATCH] Fix Non Full Status Chunk NBT Memory Leak - -Any full status chunk that was requested for any status less than full -would hold onto their entire nbt tree and every variable in that function. - -This was due to use of a lambda that persists on the Chunk object -until that chunk reaches FULL status. - -With introduction of no tick, we greatly increased the number of non -full chunks so this was really starting to hurt. - -We further improve it by making a copy of the nbt tag with only the memory -it needs, so that we dont have to hold a copy to the entire compound. - -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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 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 -@@ -0,0 +0,0 @@ import net.minecraft.nbt.CompoundTag; - import net.minecraft.nbt.ListTag; - import net.minecraft.nbt.LongArrayTag; - import net.minecraft.nbt.ShortTag; -+import net.minecraft.nbt.Tag; - import net.minecraft.server.level.ServerChunkCache; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.server.level.ThreadedLevelLightEngine; -@@ -0,0 +0,0 @@ public class ChunkSerializer { - object2 = protochunkticklist1; - } - -- object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, (chunk) -> { -- ChunkSerializer.postLoadChunk(world, nbttagcompound1, chunk); -- // CraftBukkit start - load chunk persistent data from nbt -- net.minecraft.nbt.Tag persistentBase = nbttagcompound1.get("ChunkBukkitValues"); -- if (persistentBase instanceof CompoundTag) { -- chunk.persistentDataContainer.putAll((CompoundTag) persistentBase); -- } -- // CraftBukkit end -- }); -+ object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys. -+ createLoadEntitiesConsumer(new SafeNBTCopy(nbttagcompound1, "TileEntities", "Entities", "ChunkBukkitValues")) // Paper - move CB Chunk PDC into here -+ );// Paper end - } else { - ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world, world); // Paper - add level - -@@ -0,0 +0,0 @@ public class ChunkSerializer { - return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading - } - } -+ // Paper start -+ -+ /** -+ * This wrapper will error out if any key is accessed that wasn't copied so we can catch it easy on an update -+ */ -+ private static class SafeNBTCopy extends CompoundTag { -+ private final java.util.Set<String> keys = new java.util.HashSet<String>(); -+ public SafeNBTCopy(CompoundTag base, String... keys) { -+ for (String key : keys) { -+ this.keys.add(key); -+ final Tag nbtBase = base.get(key); -+ if (nbtBase != null) { -+ this.put(key, nbtBase); -+ } -+ } -+ } -+ -+ @Override -+ public boolean contains(String key) { -+ if (super.contains(key)) { -+ return true; -+ } else if (keys.contains(key)) { -+ return false; -+ } -+ throw new IllegalStateException("Missing Key " + key + " in SafeNBTCopy"); -+ } -+ -+ @Override -+ public boolean contains(String key, int type) { -+ return contains(key) && super.contains(key, type); -+ } -+ } -+ private static java.util.function.Consumer<LevelChunk> createLoadEntitiesConsumer(CompoundTag nbt) { -+ return (chunk) -> { -+ postLoadChunk(chunk.level, nbt, chunk); -+ // CraftBukkit start - load chunk persistent data from nbt -+ Tag persistentBase = nbt.get("ChunkBukkitValues"); -+ if (persistentBase instanceof CompoundTag) { -+ chunk.persistentDataContainer.putAll((CompoundTag) persistentBase); -+ } -+ // CraftBukkit end -+ }; -+ } -+ // Paper end - - // Paper start - async chunk save for unload - public static final class AsyncSaveData { diff --git a/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch b/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch deleted file mode 100644 index ba64bfac46..0000000000 --- a/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf <Spottedleaf@users.noreply.github.com> -Date: Thu, 16 Apr 2020 16:13:59 -0700 -Subject: [PATCH] Optimize ServerLevels chunk level checking methods - -These can be hot functions (i.e entity ticking and block ticking), -so inline where possible, and avoid the abstraction of the -Either class. - -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { - public boolean isPositionTickingWithEntitiesLoaded(BlockPos blockposition) { - long i = ChunkPos.asLong(blockposition); - -- return this.chunkSource.isPositionTicking(i) && this.areEntitiesLoaded(i); -+ // Paper start - optimize is ticking ready type functions -+ ChunkHolder chunkHolder = this.chunkSource.chunkMap.getVisibleChunkIfPresent(i); -+ return chunkHolder != null && chunkHolder.isTickingReady() && this.areEntitiesLoaded(i); -+ // Paper end - } - - public boolean isPositionEntityTicking(BlockPos blockposition) { -- return this.entityManager.isPositionTicking(blockposition); -+ return this.entityManager.isPositionTicking(ChunkPos.asLong(blockposition)); // Paper - } - - public boolean isPositionEntityTicking(ChunkPos chunkcoordintpair) { -- return this.entityManager.isPositionTicking(chunkcoordintpair); -+ return this.entityManager.isPositionTicking(chunkcoordintpair.toLong()); // Paper - } - - private final class EntityCallbacks implements LevelCallback<Entity> { -diff --git a/src/main/java/net/minecraft/world/level/ChunkPos.java b/src/main/java/net/minecraft/world/level/ChunkPos.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/ChunkPos.java -+++ b/src/main/java/net/minecraft/world/level/ChunkPos.java -@@ -0,0 +0,0 @@ public class ChunkPos { - } - - public static long asLong(BlockPos blockPos) { -- return asLong(SectionPos.blockToSectionCoord(blockPos.getX()), SectionPos.blockToSectionCoord(blockPos.getZ())); -+ return (((long)blockPos.getX() >> 4) & 4294967295L) | ((((long)blockPos.getZ() >> 4) & 4294967295L) << 32); // Paper - inline - } - - public static int getX(long pos) { -diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A - public LevelEntityGetter<T> getEntityGetter() { - return this.entityGetter; - } -+ // Paper start -+ public final boolean isPositionTicking(long position) { -+ return this.chunkVisibility.get(position).isTicking(); -+ } -+ // Paper end - - public boolean isPositionTicking(BlockPos blockposition) { - return ((Visibility) this.chunkVisibility.get(ChunkPos.asLong(blockposition))).isTicking(); diff --git a/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch b/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch deleted file mode 100644 index a5829a290c..0000000000 --- a/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch +++ /dev/null @@ -1,375 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf <Spottedleaf@users.noreply.github.com> -Date: Tue, 5 May 2020 20:40:53 -0700 -Subject: [PATCH] Optimize isOutsideRange to use distance maps - -Use a distance map to find the players in range quickly - -diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java -+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -0,0 +0,0 @@ public class ChunkHolder { - } - // Paper end - -+ // Paper start - optimise isOutsideOfRange -+ // cached here to avoid a map lookup -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange; -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange; -+ -+ void updateRanges() { -+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); -+ this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); -+ this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); -+ } -+ // Paper end - optimise isOutsideOfRange -+ - public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) { - this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size()); - this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE; -@@ -0,0 +0,0 @@ public class ChunkHolder { - this.setTicketLevel(level); - this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()]; - this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper -+ this.updateRanges(); // Paper - optimise isOutsideOfRange - } - - // CraftBukkit start -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return MinecraftServer.getServer().getScaledTrackingDistance(vanilla); - } - // Paper end - use distance map to optimise tracker -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ // A note about the naming used here: -+ // Previously, mojang used a "spawn range" of 8 for controlling both ticking and -+ // mob spawn range. However, spigot makes the spawn range configurable by -+ // checking if the chunk is in the tick range (8) and the spawn range -+ // 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; -+ // Paper end - optimise PlayerChunkMap#isOutsideRange - - void addPlayerToDistanceMaps(ServerPlayer player) { - int chunkX = MCUtil.getChunkCoordinate(player.getX()); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance())); - } - // Paper end - use distance map to optimise entity tracker -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); -+ // Paper end - optimise PlayerChunkMap#isOutsideRange -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); -+ // Paper end - optimise PlayerChunkMap#isOutsideRange - // Paper start - no-tick view distance - int effectiveTickViewDistance = this.getEffectiveViewDistance(); - int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerEntityTrackerTrackMaps[i].remove(player); - } - // Paper end - use distance map to optimise tracker -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ this.playerMobSpawnMap.remove(player); -+ this.playerChunkTickRangeMap.remove(player); -+ // Paper end - optimise PlayerChunkMap#isOutsideRange - // Paper start - no-tick view distance - this.playerViewDistanceBroadcastMap.remove(player); - this.playerViewDistanceTickMap.remove(player); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance())); - } - // Paper end - use distance map to optimise entity tracker -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); -+ // Paper end - optimise PlayerChunkMap#isOutsideRange - // Paper start - no-tick view distance - int effectiveTickViewDistance = this.getEffectiveViewDistance(); - int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false); - this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper - this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false)); -- this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); -+ this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.distanceManager.chunkMap = this; // Paper - this.overworldDataStorage = persistentStateManagerFactory; - this.poiManager = new PoiManager(new File(file, "poi"), dataFixer, dsync, world); - this.setViewDistance(viewDistance); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); - } - // Paper end - use distance map to optimise entity tracker -+ // Paper start - optimise PlayerChunkMap#isOutsideRange -+ 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<ServerPlayer> 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<ServerPlayer> 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<ServerPlayer> 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<ServerPlayer> newState) -> { -+ ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ)); -+ if (playerChunk != null) { -+ playerChunk.playersInMobSpawnRange = newState; -+ } -+ }); -+ // Paper end - optimise PlayerChunkMap#isOutsideRange - } - - // Paper start -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } else { - if (holder != null) { - holder.setTicketLevel(level); -+ holder.updateRanges(); // Paper - optimise isOutsideOfRange - } - - if (holder != null) { -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - return this.isOutsideOfRange(chunkPos, false); - } - -- boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) { -- int chunkRange = level.spigotConfig.mobSpawnRange; -- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; -- chunkRange = (chunkRange > 8) ? 8 : chunkRange; -+ // Paper start - optimise isOutsideOfRange -+ final boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) { -+ return this.isOutsideOfRange(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange); -+ } -+ final boolean isOutsideOfRange(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) { -+ // 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<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange; -+ if (playersInRange == null) { -+ return true; -+ } -+ Object[] backingSet = playersInRange.getBackingSet(); - -- final int finalChunkRange = chunkRange; // Paper for lambda below -- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event -- // Spigot end -- long i = chunkcoordintpair.toLong(); -- -- return !this.distanceManager.hasPlayersNearby(i) ? true : this.playerMap.getPlayers(i).noneMatch((entityplayer) -> { -- // Paper start - add PlayerNaturallySpawnCreaturesEvent -- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; -- double blockRange = 16384.0D; -- if (reducedRange) { -- event = entityplayer.playerNaturallySpawnedEvent; -- if (event == null || event.isCancelled()) return false; -- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); -+ if (reducedRange) { -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object raw = backingSet[i]; -+ if (!(raw instanceof ServerPlayer)) { -+ continue; -+ } -+ ServerPlayer player = (ServerPlayer) raw; -+ // don't check spectator and whatnot, already handled by mob spawn map update -+ if (player.lastEntitySpawnRadiusSquared > euclideanDistanceSquared(chunkcoordintpair, player)) { -+ return false; // in range -+ } - } -- // Paper end -- return !entityplayer.isSpectator() && ChunkMap.euclideanDistanceSquared(chunkcoordintpair, (Entity) entityplayer) < blockRange; // Spigot -- }); -+ } else { -+ final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16); -+ // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split -+ for (int i = 0, len = backingSet.length; i < len; ++i) { -+ Object raw = backingSet[i]; -+ if (!(raw instanceof ServerPlayer)) { -+ continue; -+ } -+ ServerPlayer player = (ServerPlayer) raw; -+ // don't check spectator and whatnot, already handled by mob spawn map update -+ if (range > euclideanDistanceSquared(chunkcoordintpair, player)) { -+ return false; // in range -+ } -+ } -+ } -+ // no players in range -+ return true; - } -+ // Paper end - optimise isOutsideOfRange - - private boolean skipPlayer(ServerPlayer player) { - return player.isSpectator() && !this.level.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS); -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap(); - public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap(); - private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker(); -- private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); -+ public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used - private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); - // Paper start use a queue, but still keep unique requirement - public final java.util.Queue<ChunkHolder> pendingChunkUpdates = new java.util.ArrayDeque<ChunkHolder>() { -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - final Executor mainThreadExecutor; - private long ticketTickCounter; - -+ ChunkMap chunkMap; // Paper -+ - protected DistanceManager(Executor workerExecutor, Executor mainThreadExecutor) { - Objects.requireNonNull(mainThreadExecutor); - ProcessorHandle<Runnable> mailbox = ProcessorHandle.of("player ticket throttler", mainThreadExecutor::execute); -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k); - - public boolean runAllUpdates(ChunkMap playerchunkmap) { -- this.naturalSpawnChunkCounter.runAllUpdates(); -+ //this.f.a(); // Paper - no longer used - this.playerTicketManager.runAllUpdates(); - int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE); - boolean flag = i != 0; -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - ((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> { - return new ObjectOpenHashSet(); - })).add(player); -- this.naturalSpawnChunkCounter.update(i, 0, true); -+ //this.f.update(i, 0, true); // Paper - no longer used - this.playerTicketManager.update(i, 0, true); - } - -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully. - if (objectset == null || objectset.isEmpty()) { // Paper - this.playersPerChunk.remove(i); -- this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); -+ //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used - this.playerTicketManager.update(i, Integer.MAX_VALUE, false); - } - -@@ -0,0 +0,0 @@ public abstract class DistanceManager { - } - - public int getNaturalSpawnChunkCount() { -- this.naturalSpawnChunkCounter.runAllUpdates(); -- return this.naturalSpawnChunkCounter.chunks.size(); -+ // Paper start - use distance map to implement -+ // note: this is the spawn chunk count -+ return this.chunkMap.playerChunkTickRangeMap.size(); -+ // Paper end - use distance map to implement - } - - public boolean hasPlayersNearby(long i) { -- this.naturalSpawnChunkCounter.runAllUpdates(); -- return this.naturalSpawnChunkCounter.chunks.containsKey(i); -+ // Paper start - use distance map to implement -+ // note: this is the is spawn chunk method -+ return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(i) != null; -+ // Paper end - use distance map to implement - } - - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - boolean flag1 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - - if (!flag) { -+ // Paper start - optimize isOutisdeRange -+ ChunkMap playerChunkMap = this.chunkMap; -+ for (ServerPlayer player : this.level.players) { -+ if (!player.affectsSpawning || player.isSpectator()) { -+ playerChunkMap.playerMobSpawnMap.remove(player); -+ continue; -+ } -+ -+ int viewDistance = this.chunkMap.getEffectiveViewDistance(); -+ -+ // copied and modified from isOutisdeRange -+ int chunkRange = level.spigotConfig.mobSpawnRange; -+ chunkRange = (chunkRange > viewDistance) ? (byte)viewDistance : chunkRange; -+ chunkRange = (chunkRange > DistanceManager.MOB_SPAWN_RANGE) ? DistanceManager.MOB_SPAWN_RANGE : chunkRange; -+ -+ 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); -+ continue; -+ } -+ -+ int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance -+ int chunkX = net.minecraft.server.MCUtil.getChunkCoordinate(player.getX()); -+ int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.getZ()); -+ -+ playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); -+ player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in isOutsideRange -+ player.playerNaturallySpawnedEvent = event; -+ } -+ // Paper end - optimize isOutisdeRange - this.level.getProfiler().push("pollingChunks"); - int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - List<ChunkHolder> list = Lists.newArrayList(this.chunkMap.getChunks()); - - Collections.shuffle(list); -- // Paper start - call player naturally spawn event -- int chunkRange = level.spigotConfig.mobSpawnRange; -- chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; -- chunkRange = Math.min(chunkRange, 8); -- for (ServerPlayer entityPlayer : this.level.players()) { -- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange); -- entityPlayer.playerNaturallySpawnedEvent.callEvent(); -- }; -- // Paper end -+ // Paper - moved natural spawn event up - this.level.timings.chunkTicks.startTiming(); // Paper - list.forEach((playerchunk) -> { - Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left(); -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - LevelChunk chunk = (LevelChunk) optional.get(); - ChunkPos chunkcoordintpair = chunk.getPos(); - -- if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.noPlayersCloseForSpawning(chunkcoordintpair)) { -+ if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange - chunk.setInhabitedTime(chunk.getInhabitedTime() + j); -- if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot -+ if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange - NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2); - } - -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -0,0 +0,0 @@ public class ServerPlayer extends Player { - // CraftBukkit end - public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - -+ public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks - public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper - boolean needsChunkCenterUpdate; // Paper - no-tick view distance - diff --git a/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch b/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch deleted file mode 100644 index c0cfeb1f02..0000000000 --- a/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar <aikar@aikar.co> -Date: Sat, 23 May 2020 17:03:41 -0400 -Subject: [PATCH] Optimize sending packets to nearby locations (sounds/effects) - -Instead of using the entire world or player list, use the distance -maps to only iterate players who are even seeing the chunk the packet -is originating from. - -This will drastically cut down on packet sending cost for worlds with -lots of players in them. - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -0,0 +0,0 @@ public abstract class PlayerList { - } - - public void broadcast(@Nullable net.minecraft.world.entity.player.Player player, double x, double y, double z, double distance, ResourceKey<Level> worldKey, Packet<?> packet) { -- for (int i = 0; i < this.players.size(); ++i) { -- ServerPlayer entityplayer = (ServerPlayer) this.players.get(i); -+ ServerLevel world = null; -+ if (player != null && player.level instanceof ServerLevel) { -+ world = (ServerLevel) player.level; -+ } - -- // CraftBukkit start - Test if player receiving packet can see the source of the packet -- if (player != null && player instanceof ServerPlayer && !entityplayer.getBukkitEntity().canSee(((ServerPlayer) player).getBukkitEntity())) { -- continue; -+ // Paper start -+ if (world == null) { -+ world = server.getLevel(worldKey); -+ } -+ net.minecraft.server.level.ChunkMap chunkMap = world != null ? world.getChunkSource().chunkMap : null; -+ Object[] backingSet; -+ if (chunkMap == null) { -+ // Really shouldn't happen... -+ backingSet = world != null ? world.players.toArray() : players.toArray(); -+ } else { -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearbyPlayers = chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(MCUtil.fastFloor(x) >> 4, MCUtil.fastFloor(z) >> 4); -+ if (nearbyPlayers == null) { -+ return; - } -+ backingSet = nearbyPlayers.getBackingSet(); -+ } -+ -+ for (Object object : backingSet) { -+ if (!(object instanceof ServerPlayer)) continue; -+ ServerPlayer entityplayer = (ServerPlayer) object; -+ // Paper end -+ -+ // CraftBukkit start - Test if player receiving packet can see the source of the packet -+ //if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { // Paper -+ //continue; // Paper -+ //} // Paper - // CraftBukkit end - -- if (entityplayer != player && entityplayer.level.dimension() == worldKey) { -+ if (entityplayer != player && entityplayer.level.dimension() == worldKey && (!(player instanceof ServerPlayer) || entityplayer.getBukkitEntity().canSee(((ServerPlayer) player).getBukkitEntity()))) { // Paper - double d4 = x - entityplayer.getX(); - double d5 = y - entityplayer.getY(); - double d6 = z - entityplayer.getZ(); diff --git a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch b/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch deleted file mode 100644 index 2bcc96b4a2..0000000000 --- a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf <Spottedleaf@users.noreply.github.com> -Date: Tue, 5 May 2020 20:18:05 -0700 -Subject: [PATCH] Use distance map to optimise entity tracker - -Use the distance map to find candidate players for tracking. - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -0,0 +0,0 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; - import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; - import net.minecraft.network.protocol.game.DebugPackets; - import net.minecraft.server.MCUtil; -+import net.minecraft.server.MinecraftServer; - import net.minecraft.server.level.progress.ChunkProgressListener; - import net.minecraft.server.network.ServerPlayerConnection; - import net.minecraft.util.CsvOutput; -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceTickMap; - public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceNoTickMap; - // Paper end - no-tick view distance -+ // Paper start - use distance map to optimise tracker -+ public static boolean isLegacyTrackingEntity(Entity entity) { -+ return entity.isLegacyTrackingEntity; -+ } -+ -+ // 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]; -+ } -+ -+ private int convertSpigotRangeToVanilla(final int vanilla) { -+ return MinecraftServer.getServer().getScaledTrackingDistance(vanilla); -+ } -+ // Paper end - use distance map to optimise tracker - - void addPlayerToDistanceMaps(ServerPlayer player) { - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); - // Note: players need to be explicitly added to distance maps before they can be updated -+ // 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, this.getEffectiveViewDistance())); -+ } -+ // Paper end - use distance map to optimise entity tracker - // Paper start - no-tick view distance - int effectiveTickViewDistance = this.getEffectiveViewDistance(); - int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - void removePlayerFromDistanceMaps(ServerPlayer player) { -- -+ // 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); -+ } -+ // Paper end - use distance map to optimise tracker - // Paper start - no-tick view distance - this.playerViewDistanceBroadcastMap.remove(player); - this.playerViewDistanceTickMap.remove(player); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); - // Note: players need to be explicitly added to distance maps before they can be updated -+ // 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, this.getEffectiveViewDistance())); -+ } -+ // Paper end - use distance map to optimise entity tracker - // Paper start - no-tick view distance - int effectiveTickViewDistance = this.getEffectiveViewDistance(); - int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }); - // Paper end - no-tick view distance - this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper -+ // 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); -+ } -+ // Paper end - use distance map to optimise entity tracker - } - - // Paper start -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void move(ServerPlayer player) { -- 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); -- } -- } -+ // Paper - delay this logic for the entity tracker tick, no need to duplicate it - - int i = SectionPos.blockToSectionCoord(player.getBlockX()); - int j = SectionPos.blockToSectionCoord(player.getBlockZ()); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker - this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); -- playerchunkmap_entitytracker.updatePlayers(this.level.players()); -+ playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players - if (entity instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entity; - -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - entity.tracker = null; // Paper - We're no longer tracked - } - -+ // 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(); -+ } -+ } finally { -+ this.level.timings.tracker2.stopTiming(); -+ } -+ } -+ // Paper end - optimised tracker -+ - protected void tick() { -+ // Paper start - optimized tracker -+ if (true) { -+ this.processTrackQueue(); -+ return; -+ } -+ // Paper end - optimized tracker - List<ServerPlayer> list = Lists.newArrayList(); - List<ServerPlayer> list1 = this.level.players(); - -@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially - DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos()); - List<Entity> list = Lists.newArrayList(); - List<Entity> list1 = Lists.newArrayList(); -- ObjectIterator objectiterator = this.entityMap.values().iterator(); -+ // Paper start - optimise entity tracker -+ // use the chunk entity list, not the whole trackedEntities map... -+ Entity[] entities = chunk.entities.getRawData(); -+ for (int i = 0, size = chunk.entities.size(); i < size; ++i) { -+ Entity entity = entities[i]; -+ if (entity == player) { -+ continue; -+ } -+ ChunkMap.TrackedEntity tracker = this.entityMap.get(entity.getId()); -+ if (tracker != null) { // dumb plugins... move on... -+ tracker.updatePlayer(player); -+ } - -- while (objectiterator.hasNext()) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); -- Entity entity = playerchunkmap_entitytracker.entity; -+ // keep the vanilla logic here - this is REQUIRED or else passengers and their vehicles disappear! -+ // (and god knows what the leash thing is) - -- if (entity != player && entity.chunkPosition().equals(chunk.getPos())) { -- playerchunkmap_entitytracker.updatePlayer(player); -- if (entity instanceof Mob && ((Mob) entity).getLeashHolder() != null) { -- list.add(entity); -- } -+ if (entity instanceof Mob && ((Mob)entity).getLeashHolder() != null) { -+ list.add(entity); -+ } - -- if (!entity.getPassengers().isEmpty()) { -- list1.add(entity); -- } -+ if (!entity.getPassengers().isEmpty()) { -+ list1.add(entity); - } - } -+ // Paper end - optimise entity tracker - - Iterator iterator; - Entity entity1; -@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially - this.lastSectionPos = SectionPos.of(entity); - } - -+ // Paper start - use distance map to optimise tracker -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> lastTrackerCandidates; -+ -+ final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) { -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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 -+ - public boolean equals(Object object) { - return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false; - } -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -0,0 +0,0 @@ import net.minecraft.network.syncher.EntityDataSerializers; - import net.minecraft.network.syncher.SynchedEntityData; - import net.minecraft.resources.ResourceKey; - import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MCUtil; - import net.minecraft.server.MinecraftServer; - import net.minecraft.server.level.ServerLevel; - import net.minecraft.server.level.ServerPlayer; -@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n - } - // Paper end - -+ // Paper start - optimise entity tracking -+ final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this); -+ -+ public boolean isLegacyTrackingEntity = false; -+ -+ public final void setLegacyTrackingEntity(final boolean isLegacyTrackingEntity) { -+ this.isLegacyTrackingEntity = isLegacyTrackingEntity; -+ } -+ -+ public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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<Entity> 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)); -+ } -+ // Paper end - optimise entity tracking -+ - public Entity(EntityType<?> type, Level world) { - this.id = Entity.ENTITY_COUNTER.incrementAndGet(); - this.passengers = ImmutableList.of(); -diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/spigotmc/TrackingRange.java -+++ b/src/main/java/org/spigotmc/TrackingRange.java -@@ -0,0 +0,0 @@ public class TrackingRange - { - return defaultRange; - } -+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return defaultRange; // Paper - enderdragon is exempt - SpigotWorldConfig config = entity.level.spigotConfig; - if ( entity instanceof ServerPlayer ) - { -@@ -0,0 +0,0 @@ public class TrackingRange - return config.miscTrackingRange; - } else - { -- if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.getLoadViewDistance(); // Paper - enderdragon is exempt - return config.otherTrackingRange; - } - } -+ -+ // Paper start - optimise entity tracking -+ // copied from above, TODO check on update -+ public static TrackingRangeType getTrackingRangeType(Entity entity) -+ { -+ if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return TrackingRangeType.ENDERDRAGON; // Paper - enderdragon is exempt -+ if ( entity instanceof ServerPlayer ) -+ { -+ return TrackingRangeType.PLAYER; -+ // Paper start - Simplify and set water mobs to animal tracking range -+ } -+ switch (entity.activationType) { -+ case RAIDER: -+ case MONSTER: -+ case FLYING_MONSTER: -+ return TrackingRangeType.MONSTER; -+ case WATER: -+ case VILLAGER: -+ case ANIMAL: -+ return TrackingRangeType.ANIMAL; -+ case MISC: -+ } -+ if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb ) -+ // Paper end -+ { -+ return TrackingRangeType.MISC; -+ } else -+ { -+ return TrackingRangeType.OTHER; -+ } -+ } -+ -+ public static enum TrackingRangeType { -+ PLAYER, -+ ANIMAL, -+ MONSTER, -+ MISC, -+ OTHER, -+ ENDERDRAGON; -+ } -+ // Paper end - optimise entity tracking - }