diff --git a/patches/server/0104-Optimize-Chunk-Ticks.patch b/patches/server/0104-Optimize-Chunk-Ticks.patch new file mode 100644 index 000000000..a18f3ec0f --- /dev/null +++ b/patches/server/0104-Optimize-Chunk-Ticks.patch @@ -0,0 +1,546 @@ +From 214748ba37598d708dfcb8df57e7f5ea0a20ab1a Mon Sep 17 00:00:00 2001 +From: William Blake Galbreath +Date: Sun, 1 Mar 2020 20:07:54 -0600 +Subject: [PATCH] Optimize Chunk Ticks + +--- + .../co/aikar/timings/WorldTimingsHandler.java | 6 +- + .../minecraft/server/ChunkMapDistance.java | 19 +- + .../minecraft/server/ChunkProviderServer.java | 254 +++++++++--------- + .../minecraft/server/EnumCreatureType.java | 26 +- + .../net/minecraft/server/PlayerChunk.java | 3 + + .../net/minecraft/server/PlayerChunkMap.java | 19 +- + .../net/minecraft/server/WorldServer.java | 1 + + 7 files changed, 183 insertions(+), 145 deletions(-) + +diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java +index 51281cfa2..37702cd51 100644 +--- a/src/main/java/co/aikar/timings/WorldTimingsHandler.java ++++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java +@@ -60,7 +60,8 @@ public class WorldTimingsHandler { + + + public final Timing miscMobSpawning; +- public final Timing chunkInhibitedRangeCheck; ++ public final Timing bigRangeCheck; // Purpur ++ public final Timing smallRangeCheck; // Purpur + public final Timing playerMobDistanceMapUpdate; + + public final Timing poiUnload; +@@ -130,7 +131,8 @@ public class WorldTimingsHandler { + countNaturalMobs = Timings.ofSafe(name + "Count natural mobs"); + + +- chunkInhibitedRangeCheck = Timings.ofSafe(name + "Chunks - Inhibited Range Check"); ++ bigRangeCheck = Timings.ofSafe(name + "Chunks - Big Range Check"); // Purpur ++ smallRangeCheck = Timings.ofSafe(name + "Chunks - Small Range Check"); // Purpur + miscMobSpawning = Timings.ofSafe(name + "Mob spawning - Misc"); + playerMobDistanceMapUpdate = Timings.ofSafe(name + "Per Player Mob Spawning - Distance Map Update"); + +diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java +index 73d157076..1c72ec1c7 100644 +--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java ++++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java +@@ -31,7 +31,7 @@ public abstract class ChunkMapDistance { + private final Long2ObjectMap> c = new Long2ObjectOpenHashMap(); + public final Long2ObjectOpenHashMap>> tickets = new Long2ObjectOpenHashMap(); + private final ChunkMapDistance.a e = new ChunkMapDistance.a(); +- private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); ++ private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); private ChunkMapDistance.b getPlayerDistanceChunkMap() { return f; } // Purpur - OBFHELPER + private final ChunkMapDistance.c g = new ChunkMapDistance.c(33); + private final java.util.Queue pendingChunkUpdates = new java.util.LinkedList<>(); // PAIL pendingChunkUpdates // Paper - use a queue + private final ChunkTaskQueueSorter i; +@@ -258,6 +258,20 @@ public abstract class ChunkMapDistance { + return this.f.a.size(); + } + ++ // Purpur start ++ public void updatePlayerDistanceChunkMap() { ++ getPlayerDistanceChunkMap().update(); ++ } ++ ++ public int getPlayerDistanceChunkMapSize() { ++ return getPlayerDistanceChunkMap().getChunks().size(); ++ } ++ ++ public boolean hasPlayersNearby(long chunk) { ++ return getPlayerDistanceChunkMap().getChunks().containsKey(chunk); ++ } ++ // Purpur end ++ + public boolean d(long i) { + this.f.a(); + return this.f.a.containsKey(i); +@@ -425,7 +439,7 @@ public abstract class ChunkMapDistance { + + class b extends ChunkMap { + +- protected final Long2ByteMap a = new Long2ByteOpenHashMap(); ++ protected final Long2ByteMap a = new Long2ByteOpenHashMap(); protected Long2ByteMap getChunks() { return a; } // Purpur - OBFHELPER + protected final int b; + + protected b(int i) { +@@ -465,6 +479,7 @@ public abstract class ChunkMapDistance { + return objectset != null && !objectset.isEmpty(); + } + ++ public void update() { a(); } // Purpur - OBFHELPER + public void a() { + this.b(Integer.MAX_VALUE); + } +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 76c7f4a50..f01abf574 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -3,7 +3,7 @@ package net.minecraft.server; + import com.google.common.annotations.VisibleForTesting; + import com.mojang.datafixers.DataFixer; + import com.mojang.datafixers.util.Either; +-import it.unimi.dsi.fastutil.objects.Object2IntMap; ++ + import java.io.File; + import java.io.IOException; + import java.util.Arrays; +@@ -15,13 +15,10 @@ import java.util.function.BooleanSupplier; + import java.util.function.Function; + import java.util.function.Supplier; + import javax.annotation.Nullable; +-import com.destroystokyo.paper.exception.ServerInternalException; +-import org.apache.logging.log4j.LogManager; +-import org.apache.logging.log4j.Logger; + + public class ChunkProviderServer extends IChunkProvider { + +- private static final int b = (int) Math.pow(17.0D, 2.0D); ++ private static final int b = (int) Math.pow(17.0D, 2.0D); private static int chunksEligibleForSpawning() { return b; } // Purpur - OBFHELPER + private static final List c = ChunkStatus.a(); static final List getPossibleChunkStatuses() { return ChunkProviderServer.c; } // Paper - OBFHELPER + private final ChunkMapDistance chunkMapDistance; + public final ChunkGenerator chunkGenerator; +@@ -610,147 +607,152 @@ public class ChunkProviderServer extends IChunkProvider { + } + + private void tickChunks() { +- long i = this.world.getTime(); +- long j = i - this.lastTickTime; +- +- this.lastTickTime = i; +- WorldData worlddata = this.world.getWorldData(); +- boolean flag = worlddata.getType() == WorldType.DEBUG_ALL_BLOCK_STATES; +- boolean flag1 = this.world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && !world.getPlayers().isEmpty(); // CraftBukkit +- +- if (!flag) { +- this.world.getMethodProfiler().enter("pollingChunks"); +- int k = this.world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED); +- BlockPosition blockposition = this.world.getSpawn(); +- boolean flag2 = world.ticksPerAnimalSpawns != 0L && worlddata.getTime() % world.ticksPerAnimalSpawns == 0L; // CraftBukkit // PAIL: TODO monster ticks +- +- this.world.getMethodProfiler().enter("naturalSpawnCount"); +- this.world.timings.countNaturalMobs.startTiming(); // Paper - timings +- int l = this.chunkMapDistance.b(); +- EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values(); +- // Paper start - per player mob spawning ++ // Purpur start ++ long tickTime = world.getTime(); ++ long tickTimeDiff = tickTime - lastTickTime; ++ lastTickTime = tickTime; ++ ++ if (world.getWorldData().getType() != WorldType.DEBUG_ALL_BLOCK_STATES) { ++ world.getMethodProfiler().enter("pollingChunks"); ++ ++ int randomTickSpeed = world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED); ++ BlockPosition worldSpawn = world.getSpawn(); ++ ++ boolean doMobSpawning = world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && !world.getPlayers().isEmpty(); ++ boolean canSpawn = (world.ticksPerAnimalSpawns != 0L && tickTime % world.ticksPerAnimalSpawns == 0L) ++ || (world.ticksPerMonsterSpawns != 0L && tickTime % world.ticksPerMonsterSpawns == 0L); ++ ++ world.getMethodProfiler().enter("naturalSpawnCount"); ++ world.timings.countNaturalMobs.startTiming(); ++ ++ chunkMapDistance.updatePlayerDistanceChunkMap(); ++ int chunksCount = chunkMapDistance.getPlayerDistanceChunkMapSize(); ++ + int[] worldMobCount; +- if (this.playerChunkMap.playerMobDistanceMap != null) { ++ if (playerChunkMap.playerMobDistanceMap != null) { + // update distance map +- this.world.timings.playerMobDistanceMapUpdate.startTiming(); +- this.playerChunkMap.playerMobDistanceMap.update(this.world.players, this.playerChunkMap.viewDistance); +- this.world.timings.playerMobDistanceMapUpdate.stopTiming(); ++ world.timings.playerMobDistanceMapUpdate.startTiming(); ++ playerChunkMap.playerMobDistanceMap.update(world.players, playerChunkMap.viewDistance); ++ world.timings.playerMobDistanceMapUpdate.stopTiming(); + // re-set mob counts +- for (EntityPlayer player : this.world.players) { ++ for (EntityPlayer player : world.players) { + Arrays.fill(player.mobCounts, 0); + } +- worldMobCount = this.world.countMobs(true); ++ worldMobCount = world.countMobs(true); + } else { +- worldMobCount = this.world.countMobs(false); ++ worldMobCount = world.countMobs(false); + } +- // Paper end + +- this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings +- this.world.getMethodProfiler().exit(); +- //Paper start - call player naturally spawn event +- int chunkRange = world.spigotConfig.mobSpawnRange; +- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange; +- chunkRange = Math.min(chunkRange, 8); +- for (EntityPlayer entityPlayer : this.world.players) { +- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange); +- entityPlayer.playerNaturallySpawnedEvent.callEvent(); +- }; +- // Paper end +- this.playerChunkMap.f().forEach((playerchunk) -> { +- Optional optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); ++ world.timings.countNaturalMobs.stopTiming(); ++ world.getMethodProfiler().exit(); // naturalSpawnCount + +- if (optional.isPresent()) { +- Chunk chunk = (Chunk) optional.get(); +- +- this.world.getMethodProfiler().enter("broadcast"); +- this.world.timings.broadcastChunkUpdates.startTiming(); // Paper - timings +- playerchunk.a(chunk); +- this.world.timings.broadcastChunkUpdates.stopTiming(); // Paper - timings +- this.world.getMethodProfiler().exit(); +- ChunkCoordIntPair chunkcoordintpair = playerchunk.i(); +- +- this.world.timings.chunkInhibitedRangeCheck.startTiming(); +- if (!this.playerChunkMap.isOutsideOfRange(chunkcoordintpair)) { +- // Paper end +- chunk.setInhabitedTime(chunk.getInhabitedTime() + j); +- if (flag1 && (this.allowMonsters || this.allowAnimals) && this.world.getWorldBorder().isInBounds(chunk.getPos()) && !this.playerChunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot +- this.world.getMethodProfiler().enter("spawner"); +- this.world.timings.mobSpawn.startTiming(); // Spigot +- EnumCreatureType[] aenumcreaturetype1 = aenumcreaturetype; +- int i1 = aenumcreaturetype.length; +- +- for (int j1 = 0; j1 < i1; ++j1) { +- EnumCreatureType enumcreaturetype = aenumcreaturetype1[j1]; +- +- // CraftBukkit start - Use per-world spawn limits +- int limit = enumcreaturetype.b(); +- switch (enumcreaturetype) { +- case MONSTER: +- limit = world.getWorld().getMonsterSpawnLimit(); +- break; +- case CREATURE: +- limit = world.getWorld().getAnimalSpawnLimit(); +- break; +- case WATER_CREATURE: +- limit = world.getWorld().getWaterAnimalSpawnLimit(); +- break; +- case AMBIENT: +- limit = world.getWorld().getAmbientSpawnLimit(); +- break; +- } +- +- if (limit == 0) { +- continue; +- } +- // CraftBukkit end +- +- if (enumcreaturetype != EnumCreatureType.MISC && (!enumcreaturetype.c() || this.allowAnimals) && (enumcreaturetype.c() || this.allowMonsters) && (!enumcreaturetype.d() || flag2)) { +- int k1 = limit * l / ChunkProviderServer.b; // CraftBukkit - use per-world limits +- +- // Paper start - only allow spawns upto the limit per chunk and update count afterwards +- int currEntityCount = worldMobCount[enumcreaturetype.ordinal()]; +- int difference = k1 - currEntityCount; +- +- if (this.world.paperConfig.perPlayerMobSpawns) { +- int minDiff = Integer.MAX_VALUE; +- for (EntityPlayer entityplayer : this.playerChunkMap.playerMobDistanceMap.getPlayersInRange(chunk.getPos())) { +- minDiff = Math.min(limit - this.playerChunkMap.getMobCountNear(entityplayer, enumcreaturetype), minDiff); +- } +- difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; +- } +- +- if (difference > 0) { +- int spawnCount = SpawnerCreature.spawnMobs(enumcreaturetype, this.world, chunk, blockposition, difference, +- this.world.paperConfig.perPlayerMobSpawns ? this.playerChunkMap::updatePlayerMobTypeMap : null); +- worldMobCount[enumcreaturetype.ordinal()] += spawnCount; +- // Paper end +- } +- } ++ byte chunkRange = (byte) Math.min(Math.min(world.spigotConfig.mobSpawnRange, world.spigotConfig.viewDistance), 8); ++ for (EntityPlayer player : world.players) { ++ player.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), chunkRange); ++ player.playerNaturallySpawnedEvent.callEvent(); ++ } ++ ++ EnumCreatureType[] creatureTypes = EnumCreatureType.values(); ++ EnumCreatureType.MONSTER.setSpigotCap(world.getWorld().getMonsterSpawnLimit()); ++ EnumCreatureType.CREATURE.setSpigotCap(world.getWorld().getAnimalSpawnLimit()); ++ EnumCreatureType.WATER_CREATURE.setSpigotCap(world.getWorld().getWaterAnimalSpawnLimit()); ++ EnumCreatureType.AMBIENT.setSpigotCap(world.getWorld().getAmbientSpawnLimit()); ++ ++ for (PlayerChunk playerchunk : playerChunkMap.getChunks()) { ++ Chunk chunk = playerchunk.getEntityTickingFuture().getNow(PlayerChunk.UNLOADED_CHUNK).left().orElse(null); ++ if (chunk == null) { ++ continue; ++ } ++ ++ world.getMethodProfiler().enter("broadcast"); ++ world.timings.broadcastChunkUpdates.startTiming(); ++ playerchunk.broadcast(chunk); ++ world.timings.broadcastChunkUpdates.stopTiming(); ++ world.getMethodProfiler().exit(); // broadcast ++ ++ ChunkCoordIntPair playerChunkPos = playerchunk.getPos(); ++ ChunkCoordIntPair chunkPos = chunk.getPos(); ++ ++ world.timings.bigRangeCheck.startTiming(); ++ boolean outsideBigRange = playerChunkMap.isOutsideOfRange(playerChunkPos); ++ world.timings.bigRangeCheck.stopTiming(); ++ if (outsideBigRange) { ++ continue; ++ } ++ ++ chunk.setInhabitedTime(chunk.getInhabitedTime() + tickTimeDiff); ++ ++ world.timings.smallRangeCheck.startTiming(); ++ boolean outsideSmallRange = playerChunkMap.isOutsideOfRange(playerChunkPos, true); ++ world.timings.smallRangeCheck.stopTiming(); ++ ++ if (!outsideSmallRange && doMobSpawning && (allowMonsters || allowAnimals) && world.getWorldBorder().isInBounds(chunkPos)) { ++ world.getMethodProfiler().enter("spawner"); ++ world.timings.mobSpawn.startTiming(); ++ for (EnumCreatureType creatureType : creatureTypes) { ++ if (creatureType == EnumCreatureType.MISC) { ++ continue; // do not spawn misc entities ++ } ++ ++ if (creatureType.isFriendly() && !allowAnimals) { ++ continue; // not allowed to spawn animals ++ } ++ ++ if (!creatureType.isFriendly() && !allowMonsters) { ++ continue; // not allowed to spawn monsters ++ } ++ ++ if (creatureType.isPersistent() && !canSpawn) { ++ continue; // skip this entity this tick ++ } ++ ++ int limit = creatureType.getSpigotCap(); ++ if (limit <= 0) { ++ continue; // entity is disabled ++ } ++ ++ int worldLimit = limit * chunksCount / chunksEligibleForSpawning(); ++ ++ int currEntityCount = worldMobCount[creatureType.ordinal()]; ++ int openSlots = worldLimit - currEntityCount; ++ ++ if (world.paperConfig.perPlayerMobSpawns) { ++ int minDiff = Integer.MAX_VALUE; ++ for (EntityPlayer player : playerChunkMap.playerMobDistanceMap.getPlayersInRange(chunkPos)) { ++ minDiff = Math.min(limit - playerChunkMap.getMobCountNear(player, creatureType), minDiff); + } ++ openSlots = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff; ++ } + +- this.world.timings.mobSpawn.stopTiming(); // Spigot +- this.world.getMethodProfiler().exit(); ++ if (openSlots <= 0) { ++ continue; // mob cap reached + } + +- this.world.timings.chunkTicks.startTiming(); // Spigot // Paper +- this.world.a(chunk, k); +- this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper ++ worldMobCount[creatureType.ordinal()] += SpawnerCreature.spawnMobs(creatureType, world, chunk, worldSpawn, openSlots, world.paperConfig.perPlayerMobSpawns ? playerChunkMap::updatePlayerMobTypeMap : null); + } +- this.world.timings.chunkInhibitedRangeCheck.stopTiming(); // Paper ++ ++ world.timings.mobSpawn.stopTiming(); ++ world.getMethodProfiler().exit(); // spawner + } +- }); +- this.world.getMethodProfiler().enter("customSpawners"); +- if (flag1) { +- try (co.aikar.timings.Timing ignored = this.world.timings.miscMobSpawning.startTiming()) { // Paper - timings +- this.chunkGenerator.doMobSpawning(this.world, this.allowMonsters, this.allowAnimals); ++ ++ world.timings.chunkTicks.startTiming(); ++ world.tickChunk(chunk, randomTickSpeed); ++ world.timings.chunkTicks.stopTiming(); ++ } ++ ++ world.getMethodProfiler().enter("customSpawners"); ++ if (doMobSpawning) { ++ try (co.aikar.timings.Timing ignored = world.timings.miscMobSpawning.startTiming()) { // Paper - timings ++ chunkGenerator.doMobSpawning(world, allowMonsters, allowAnimals); + } // Paper - timings + } ++ world.getMethodProfiler().exit(); // customSpawners + +- this.world.getMethodProfiler().exit(); +- this.world.getMethodProfiler().exit(); ++ world.getMethodProfiler().exit(); // pollingChunks + } + +- this.playerChunkMap.g(); ++ playerChunkMap.tick(); ++ // Purpur end + } + + @Override +diff --git a/src/main/java/net/minecraft/server/EnumCreatureType.java b/src/main/java/net/minecraft/server/EnumCreatureType.java +index 3ed7fa324..d22d70bb4 100644 +--- a/src/main/java/net/minecraft/server/EnumCreatureType.java ++++ b/src/main/java/net/minecraft/server/EnumCreatureType.java +@@ -6,11 +6,13 @@ import java.util.stream.Collectors; + + public enum EnumCreatureType { + +- MONSTER("monster", 70, false, false), CREATURE("creature", 10, true, true), AMBIENT("ambient", 15, true, false), WATER_CREATURE("water_creature", 15, true, false), MISC("misc", 15, true, false); ++ MONSTER("monster", 70, false, false), ++ CREATURE("creature", 10, true, true), ++ AMBIENT("ambient", 15, true, false), ++ WATER_CREATURE("water_creature", 15, true, false), ++ MISC("misc", 15, true, false); + +- private static final Map f = (Map) Arrays.stream(values()).collect(Collectors.toMap(EnumCreatureType::a, (enumcreaturetype) -> { +- return enumcreaturetype; +- })); ++ private static final Map f = Arrays.stream(values()).collect(Collectors.toMap(EnumCreatureType::a, (enumcreaturetype) -> enumcreaturetype)); // Purpur - decompile error + private final int g; + private final boolean h; + private final boolean i; +@@ -23,19 +25,35 @@ public enum EnumCreatureType { + this.i = flag1; + } + ++ public String getName() { return a(); } // Purpur - OBFHELPER + public String a() { + return this.j; + } + ++ public int getSpawnCap() { return b(); } // Purpur - OBFHELPER + public int b() { + return this.g; + } + ++ public boolean isFriendly() { return c(); } // Purpur - OBFHELPER + public boolean c() { + return this.h; + } + ++ public boolean isPersistent() { return d(); } // Purpur - OBFHELPER + public boolean d() { + return this.i; + } ++ ++ // Purpur start ++ private int spigotCap = -1; ++ ++ void setSpigotCap(int cap) { ++ this.spigotCap = cap; ++ } ++ ++ int getSpigotCap() { ++ return this.spigotCap; ++ } ++ // Purpur end + } +diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java +index b82ea26eb..1fc8f4b08 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunk.java ++++ b/src/main/java/net/minecraft/server/PlayerChunk.java +@@ -155,6 +155,7 @@ public class PlayerChunk { + return this.tickingFuture; + } + ++ public CompletableFuture> getEntityTickingFuture() { return b(); } // Purpur - OBFHELPER + public CompletableFuture> b() { + return this.entityTickingFuture; + } +@@ -227,6 +228,7 @@ public class PlayerChunk { + } + } + ++ public void broadcast(Chunk chunk) { a(chunk); } // Purpur - OBFHELPER + public void a(Chunk chunk) { + if (this.dirtyCount != 0 || this.u != 0 || this.t != 0) { + World world = chunk.getWorld(); +@@ -342,6 +344,7 @@ public class PlayerChunk { + }); + } + ++ public ChunkCoordIntPair getPos() { return i(); } // Purpur - OBFHELPER + public ChunkCoordIntPair i() { + return this.location; + } +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index 57bea926a..ffcdc0b4a 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -1069,6 +1069,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + return this.chunkDistanceManager; + } + ++ protected Iterable getChunks() { return f(); } // Purpur - OBFHELPER + protected Iterable f() { + return Iterables.unmodifiableIterable(this.visibleChunks.values()); + } +@@ -1266,26 +1267,21 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + } + + boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) { +- int chunkRange = world.spigotConfig.mobSpawnRange; +- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange; +- chunkRange = (chunkRange > 8) ? 8 : chunkRange; +- +- final int finalChunkRange = chunkRange; // Paper for lambda below +- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event ++ // Purpur - removed a bunch of crap not used anymore + // Spigot end + long i = chunkcoordintpair.pair(); + +- return !this.chunkDistanceManager.d(i) ? true : this.playerMap.a(i).noneMatch((entityplayer) -> { ++ return !this.chunkDistanceManager.hasPlayersNearby(i) || this.playerMap.a(i).noneMatch((entityplayer) -> { // Purpur + // Paper start - +- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; ++ // com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event // Purpur - moved down + double blockRange = 16384.0D; + if (reducedRange) { +- event = entityplayer.playerNaturallySpawnedEvent; ++ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = entityplayer.playerNaturallySpawnedEvent; // Purpur + if (event == null || event.isCancelled()) return false; +- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); ++ blockRange = (event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4); // Purpur - removed pointless cast + } + +- return (!entityplayer.isSpectator() && a(chunkcoordintpair, (Entity) entityplayer) < blockRange); // Spigot ++ return !entityplayer.isSpectator() && a(chunkcoordintpair, entityplayer) < blockRange; // Spigot // Purpur - remove pointless cast + // Paper end + }); + } +@@ -1496,6 +1492,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + entity.tracker = null; // Paper - We're no longer tracked + } + ++ protected void tick() { g(); } // Purpur - OBFHELPER + protected void g() { + List list = Lists.newArrayList(); + List list1 = this.world.getPlayers(); +diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java +index 456c835c8..ccb6372ab 100644 +--- a/src/main/java/net/minecraft/server/WorldServer.java ++++ b/src/main/java/net/minecraft/server/WorldServer.java +@@ -537,6 +537,7 @@ public class WorldServer extends World { + private final com.destroystokyo.paper.util.math.ThreadUnsafeRandom randomTickRandom = new com.destroystokyo.paper.util.math.ThreadUnsafeRandom(); + // Paper end + ++ public void tickChunk(Chunk chunk, int randomTickSpeed) { a(chunk, randomTickSpeed); } // Purpur - OBFHELPER + public void a(Chunk chunk, int i) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + boolean flag = this.isRaining(); +-- +2.24.0 + diff --git a/patches/server/0104-Optimize-PlayerChunkMap.patch b/patches/server/0104-Optimize-PlayerChunkMap.patch deleted file mode 100644 index 636593eff..000000000 --- a/patches/server/0104-Optimize-PlayerChunkMap.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 349a2932baf2172b796df1b0956629a11286c9b8 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 1 Mar 2020 20:07:54 -0600 -Subject: [PATCH] Optimize PlayerChunkMap - ---- - .../net/minecraft/server/ChunkMapDistance.java | 12 ++++++++++-- - .../minecraft/server/ChunkProviderServer.java | 17 +++++------------ - .../net/minecraft/server/PlayerChunkMap.java | 17 ++++++----------- - 3 files changed, 21 insertions(+), 25 deletions(-) - -diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java -index 73d1570765..78735ba56e 100644 ---- a/src/main/java/net/minecraft/server/ChunkMapDistance.java -+++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java -@@ -31,7 +31,7 @@ public abstract class ChunkMapDistance { - private final Long2ObjectMap> c = new Long2ObjectOpenHashMap(); - public final Long2ObjectOpenHashMap>> tickets = new Long2ObjectOpenHashMap(); - private final ChunkMapDistance.a e = new ChunkMapDistance.a(); -- private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); -+ private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); private ChunkMapDistance.b getPlayerDistanceChunkMap() { return f; } // Purpur - OBFHELPER - private final ChunkMapDistance.c g = new ChunkMapDistance.c(33); - private final java.util.Queue pendingChunkUpdates = new java.util.LinkedList<>(); // PAIL pendingChunkUpdates // Paper - use a queue - private final ChunkTaskQueueSorter i; -@@ -258,6 +258,13 @@ public abstract class ChunkMapDistance { - return this.f.a.size(); - } - -+ // Purpur start -+ public boolean hasPlayersNearby(long chunk, boolean update) { -+ if (update) getPlayerDistanceChunkMap().update(); -+ return getPlayerDistanceChunkMap().getChunks().containsKey(chunk); -+ } -+ // Purpur end -+ - public boolean d(long i) { - this.f.a(); - return this.f.a.containsKey(i); -@@ -425,7 +432,7 @@ public abstract class ChunkMapDistance { - - class b extends ChunkMap { - -- protected final Long2ByteMap a = new Long2ByteOpenHashMap(); -+ protected final Long2ByteMap a = new Long2ByteOpenHashMap(); protected Long2ByteMap getChunks() { return a; } // Purpur - OBFHELPER - protected final int b; - - protected b(int i) { -@@ -465,6 +472,7 @@ public abstract class ChunkMapDistance { - return objectset != null && !objectset.isEmpty(); - } - -+ public void update() { a(); } // Purpur - OBFHELPER - public void a() { - this.b(Integer.MAX_VALUE); - } -diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 76c7f4a50f..dff40c04cd 100644 ---- a/src/main/java/net/minecraft/server/ChunkProviderServer.java -+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -648,19 +648,17 @@ public class ChunkProviderServer extends IChunkProvider { - this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings - this.world.getMethodProfiler().exit(); - //Paper start - call player naturally spawn event -- int chunkRange = world.spigotConfig.mobSpawnRange; -- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange; -- chunkRange = Math.min(chunkRange, 8); -+ byte chunkRange = (byte) Math.min(Math.min(world.spigotConfig.mobSpawnRange, world.spigotConfig.viewDistance), 8); // Purpur - for (EntityPlayer entityPlayer : this.world.players) { -- entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange); -+ entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), chunkRange); // Purpur - remove pointless cast - entityPlayer.playerNaturallySpawnedEvent.callEvent(); - }; - // Paper end - this.playerChunkMap.f().forEach((playerchunk) -> { -- Optional optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); -+ Optional optional = playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK).left(); // Purpur - remove pointless cast - - if (optional.isPresent()) { -- Chunk chunk = (Chunk) optional.get(); -+ Chunk chunk = optional.get(); // Purpur - remove pointless cast - - this.world.getMethodProfiler().enter("broadcast"); - this.world.timings.broadcastChunkUpdates.startTiming(); // Paper - timings -@@ -676,12 +674,7 @@ public class ChunkProviderServer extends IChunkProvider { - if (flag1 && (this.allowMonsters || this.allowAnimals) && this.world.getWorldBorder().isInBounds(chunk.getPos()) && !this.playerChunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot - this.world.getMethodProfiler().enter("spawner"); - this.world.timings.mobSpawn.startTiming(); // Spigot -- EnumCreatureType[] aenumcreaturetype1 = aenumcreaturetype; -- int i1 = aenumcreaturetype.length; -- -- for (int j1 = 0; j1 < i1; ++j1) { -- EnumCreatureType enumcreaturetype = aenumcreaturetype1[j1]; -- -+ for (EnumCreatureType enumcreaturetype : aenumcreaturetype) { // Purpur - // CraftBukkit start - Use per-world spawn limits - int limit = enumcreaturetype.b(); - switch (enumcreaturetype) { -diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 57bea926a6..44c2ca1184 100644 ---- a/src/main/java/net/minecraft/server/PlayerChunkMap.java -+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java -@@ -1266,26 +1266,21 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { - } - - boolean isOutsideOfRange(ChunkCoordIntPair chunkcoordintpair, boolean reducedRange) { -- int chunkRange = world.spigotConfig.mobSpawnRange; -- chunkRange = (chunkRange > world.spigotConfig.viewDistance) ? (byte) world.spigotConfig.viewDistance : chunkRange; -- chunkRange = (chunkRange > 8) ? 8 : chunkRange; -- -- final int finalChunkRange = chunkRange; // Paper for lambda below -- //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event -+ // Purpur - removed a bunch of crap not used anymore - // Spigot end - long i = chunkcoordintpair.pair(); - -- return !this.chunkDistanceManager.d(i) ? true : this.playerMap.a(i).noneMatch((entityplayer) -> { -+ return !this.chunkDistanceManager.hasPlayersNearby(i, !reducedRange) || this.playerMap.a(i).noneMatch((entityplayer) -> { // Purpur - // Paper start - -- com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; -+ // com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event // Purpur - moved down - double blockRange = 16384.0D; - if (reducedRange) { -- event = entityplayer.playerNaturallySpawnedEvent; -+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = entityplayer.playerNaturallySpawnedEvent; // Purpur - if (event == null || event.isCancelled()) return false; -- blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4)); -+ blockRange = (event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4); // Purpur - removed pointless cast - } - -- return (!entityplayer.isSpectator() && a(chunkcoordintpair, (Entity) entityplayer) < blockRange); // Spigot -+ return !entityplayer.isSpectator() && a(chunkcoordintpair, entityplayer) < blockRange; // Spigot // Purpur - remove pointless cast - // Paper end - }); - } --- -2.24.0 -