diff options
Diffstat (limited to 'patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch')
-rw-r--r-- | patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch | 1896 |
1 files changed, 1896 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch b/patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch new file mode 100644 index 0000000000..0eb9c2a4f2 --- /dev/null +++ b/patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch @@ -0,0 +1,1896 @@ +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -100,6 +100,9 @@ + import net.minecraft.world.phys.Vec3; + import org.apache.commons.lang3.mutable.MutableBoolean; + import org.slf4j.Logger; ++import org.bukkit.craftbukkit.generator.CustomChunkGenerator; ++import org.bukkit.entity.Player; ++// CraftBukkit end + + public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider { + +@@ -113,38 +116,59 @@ + public static final int MIN_VIEW_DISTANCE = 2; + public static final int MAX_VIEW_DISTANCE = 32; + public static final int FORCED_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING); +- private final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); +- private volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; ++ public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); ++ public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; + private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads; + private final LongSet entitiesInLevel; +- final ServerLevel level; ++ public final ServerLevel level; + private final ThreadedLevelLightEngine lightEngine; + private final BlockableEventLoop<Runnable> mainThreadExecutor; +- private ChunkGenerator generator; ++ public ChunkGenerator generator; + private final RandomState randomState; + private final ChunkGeneratorStructureState chunkGeneratorState; + private final Supplier<DimensionDataStorage> overworldDataStorage; + private final PoiManager poiManager; +- final LongSet toDrop; ++ public final LongSet toDrop; + private boolean modified; + private final ChunkTaskPriorityQueueSorter queueSorter; + private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox; + private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox; +- private final ChunkProgressListener progressListener; ++ public final ChunkProgressListener progressListener; + private final ChunkStatusUpdateListener chunkStatusListener; +- private final ChunkMap.DistanceManager distanceManager; ++ public final ChunkMap.DistanceManager distanceManager; + private final AtomicInteger tickingGenerated; + private final StructureTemplateManager structureTemplateManager; + private final String storageName; + private final PlayerMap playerMap; +- private final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap; ++ public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap; + private final Long2ByteMap chunkTypeCache; + private final Long2LongMap chunkSaveCooldowns; + private final Queue<Runnable> unloadQueue; + private int serverViewDistance; + +- public ChunkMap(ServerLevel serverlevel, LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, DataFixer datafixer, StructureTemplateManager structuretemplatemanager, Executor executor, BlockableEventLoop<Runnable> blockableeventloop, LightChunkGetter lightchunkgetter, ChunkGenerator chunkgenerator, ChunkProgressListener chunkprogresslistener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier<DimensionDataStorage> supplier, int i, boolean flag) { +- super(levelstoragesource_levelstorageaccess.getDimensionPath(serverlevel.dimension()).resolve("region"), datafixer, flag); ++ // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() ++ public final CallbackExecutor callbackExecutor = new CallbackExecutor(); ++ public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable { ++ ++ private final java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>(); ++ ++ @Override ++ public void execute(Runnable runnable) { ++ queue.add(runnable); ++ } ++ ++ @Override ++ public void run() { ++ Runnable task; ++ while ((task = queue.poll()) != null) { ++ task.run(); ++ } ++ } ++ }; ++ // CraftBukkit end ++ ++ public ChunkMap(ServerLevel level, LevelStorageSource.LevelStorageAccess levelStorageAccess, DataFixer fixerUpper, StructureTemplateManager structureManager, Executor dispatcher, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter lightChunk, ChunkGenerator generator, ChunkProgressListener progressListener, ChunkStatusUpdateListener chunkStatusListener, Supplier<DimensionDataStorage> overworldDataStorage, int viewDistance, boolean sync) { ++ super(levelStorageAccess.getDimensionPath(level.dimension()).resolve("region"), fixerUpper, sync); + this.visibleChunkMap = this.updatingChunkMap.clone(); + this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); + this.entitiesInLevel = new LongOpenHashSet(); +@@ -155,42 +179,47 @@ + this.chunkTypeCache = new Long2ByteOpenHashMap(); + this.chunkSaveCooldowns = new Long2LongOpenHashMap(); + this.unloadQueue = Queues.newConcurrentLinkedQueue(); +- this.structureTemplateManager = structuretemplatemanager; +- Path path = levelstoragesource_levelstorageaccess.getDimensionPath(serverlevel.dimension()); ++ this.structureTemplateManager = structureManager; ++ Path path = levelStorageAccess.getDimensionPath(level.dimension()); + + this.storageName = path.getFileName().toString(); +- this.level = serverlevel; +- this.generator = chunkgenerator; +- RegistryAccess registryaccess = serverlevel.registryAccess(); +- long j = serverlevel.getSeed(); ++ this.level = level; ++ this.generator = generator; ++ // CraftBukkit start - SPIGOT-7051: It's a rigged game! Use delegate for random state creation, otherwise it is not so random. ++ if (generator instanceof CustomChunkGenerator) { ++ generator = ((CustomChunkGenerator) generator).getDelegate(); ++ } ++ // CraftBukkit end ++ RegistryAccess iregistrycustom = level.registryAccess(); ++ long j = level.getSeed(); + +- if (chunkgenerator instanceof NoiseBasedChunkGenerator) { +- NoiseBasedChunkGenerator noisebasedchunkgenerator = (NoiseBasedChunkGenerator) chunkgenerator; ++ if (generator instanceof NoiseBasedChunkGenerator) { ++ NoiseBasedChunkGenerator chunkgeneratorabstract = (NoiseBasedChunkGenerator) generator; + +- this.randomState = RandomState.create((NoiseGeneratorSettings) noisebasedchunkgenerator.generatorSettings().value(), (HolderGetter) registryaccess.lookupOrThrow(Registries.NOISE), j); ++ this.randomState = RandomState.create((NoiseGeneratorSettings) chunkgeneratorabstract.generatorSettings().value(), (HolderGetter) iregistrycustom.lookupOrThrow(Registries.NOISE), j); + } else { +- this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), (HolderGetter) registryaccess.lookupOrThrow(Registries.NOISE), j); ++ this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), (HolderGetter) iregistrycustom.lookupOrThrow(Registries.NOISE), j); + } + +- this.chunkGeneratorState = chunkgenerator.createState(registryaccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j); +- this.mainThreadExecutor = blockableeventloop; +- ProcessorMailbox<Runnable> processormailbox = ProcessorMailbox.create(executor, "worldgen"); ++ this.chunkGeneratorState = generator.createState(iregistrycustom.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j); ++ this.mainThreadExecutor = mainThreadExecutor; ++ ProcessorMailbox<Runnable> threadedmailbox = ProcessorMailbox.create(dispatcher, "worldgen"); + +- Objects.requireNonNull(blockableeventloop); +- ProcessorHandle<Runnable> processorhandle = ProcessorHandle.of("main", blockableeventloop::tell); ++ Objects.requireNonNull(mainThreadExecutor); ++ ProcessorHandle<Runnable> mailbox = ProcessorHandle.of("main", mainThreadExecutor::tell); + +- this.progressListener = chunkprogresslistener; +- this.chunkStatusListener = chunkstatusupdatelistener; +- ProcessorMailbox<Runnable> processormailbox1 = ProcessorMailbox.create(executor, "light"); ++ this.progressListener = progressListener; ++ this.chunkStatusListener = chunkStatusListener; ++ ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(dispatcher, "light"); + +- this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(processormailbox, processorhandle, processormailbox1), executor, Integer.MAX_VALUE); +- this.worldgenMailbox = this.queueSorter.getProcessor(processormailbox, false); +- this.mainThreadMailbox = this.queueSorter.getProcessor(processorhandle, false); +- this.lightEngine = new ThreadedLevelLightEngine(lightchunkgetter, this, this.level.dimensionType().hasSkyLight(), processormailbox1, this.queueSorter.getProcessor(processormailbox1, false)); +- this.distanceManager = new ChunkMap.DistanceManager(executor, blockableeventloop); +- this.overworldDataStorage = supplier; +- this.poiManager = new PoiManager(path.resolve("poi"), datafixer, flag, registryaccess, serverlevel); +- this.setServerViewDistance(i); ++ this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), dispatcher, Integer.MAX_VALUE); ++ this.worldgenMailbox = this.queueSorter.getProcessor(threadedmailbox, false); ++ this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false); ++ this.lightEngine = new ThreadedLevelLightEngine(lightChunk, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false)); ++ this.distanceManager = new ChunkMap.DistanceManager(dispatcher, mainThreadExecutor); ++ this.overworldDataStorage = overworldDataStorage; ++ this.poiManager = new PoiManager(path.resolve("poi"), fixerUpper, sync, iregistrycustom, level); ++ this.setServerViewDistance(viewDistance); + } + + protected ChunkGenerator generator() { +@@ -216,26 +245,26 @@ + }); + } + +- private static double euclideanDistanceSquared(ChunkPos chunkpos, Entity entity) { +- double d0 = (double) SectionPos.sectionToBlockCoord(chunkpos.x, 8); +- double d1 = (double) SectionPos.sectionToBlockCoord(chunkpos.z, 8); ++ private static double euclideanDistanceSquared(ChunkPos chunkPos, Entity entity) { ++ double d0 = (double) SectionPos.sectionToBlockCoord(chunkPos.x, 8); ++ double d1 = (double) SectionPos.sectionToBlockCoord(chunkPos.z, 8); + double d2 = d0 - entity.getX(); + double d3 = d1 - entity.getZ(); + + return d2 * d2 + d3 * d3; + } + +- boolean isChunkTracked(ServerPlayer serverplayer, int i, int j) { +- return serverplayer.getChunkTrackingView().contains(i, j) && !serverplayer.connection.chunkSender.isPending(ChunkPos.asLong(i, j)); ++ boolean isChunkTracked(ServerPlayer entityplayer, int i, int j) { ++ return entityplayer.getChunkTrackingView().contains(i, j) && !entityplayer.connection.chunkSender.isPending(ChunkPos.asLong(i, j)); + } + +- private boolean isChunkOnTrackedBorder(ServerPlayer serverplayer, int i, int j) { +- if (!this.isChunkTracked(serverplayer, i, j)) { ++ private boolean isChunkOnTrackedBorder(ServerPlayer entityplayer, int i, int j) { ++ if (!this.isChunkTracked(entityplayer, i, j)) { + return false; + } else { + for (int k = -1; k <= 1; ++k) { + for (int l = -1; l <= 1; ++l) { +- if ((k != 0 || l != 0) && !this.isChunkTracked(serverplayer, i + k, j + l)) { ++ if ((k != 0 || l != 0) && !this.isChunkTracked(entityplayer, i + k, j + l)) { + return true; + } + } +@@ -250,93 +279,95 @@ + } + + @Nullable +- protected ChunkHolder getUpdatingChunkIfPresent(long i) { +- return (ChunkHolder) this.updatingChunkMap.get(i); ++ protected ChunkHolder getUpdatingChunkIfPresent(long chunkPos) { ++ return (ChunkHolder) this.updatingChunkMap.get(chunkPos); + } + + @Nullable +- protected ChunkHolder getVisibleChunkIfPresent(long i) { +- return (ChunkHolder) this.visibleChunkMap.get(i); ++ protected ChunkHolder getVisibleChunkIfPresent(long chunkPos) { ++ return (ChunkHolder) this.visibleChunkMap.get(chunkPos); + } + +- protected IntSupplier getChunkQueueLevel(long i) { ++ protected IntSupplier getChunkQueueLevel(long chunkPos) { + return () -> { +- ChunkHolder chunkholder = this.getVisibleChunkIfPresent(i); ++ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(chunkPos); + +- return chunkholder == null ? ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1 : Math.min(chunkholder.getQueueLevel(), ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1); ++ return playerchunk == null ? ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1 : Math.min(playerchunk.getQueueLevel(), ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1); + }; + } + +- public String getChunkDebugData(ChunkPos chunkpos) { +- ChunkHolder chunkholder = this.getVisibleChunkIfPresent(chunkpos.toLong()); ++ public String getChunkDebugData(ChunkPos pos) { ++ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); + +- if (chunkholder == null) { ++ if (playerchunk == null) { + return "null"; + } else { +- String s = chunkholder.getTicketLevel() + "\n"; +- ChunkStatus chunkstatus = chunkholder.getLastAvailableStatus(); +- ChunkAccess chunkaccess = chunkholder.getLastAvailable(); ++ String s = playerchunk.getTicketLevel() + "\n"; ++ ChunkStatus chunkstatus = playerchunk.getLastAvailableStatus(); ++ ChunkAccess ichunkaccess = playerchunk.getLastAvailable(); + + if (chunkstatus != null) { + s = s + "St: \u00a7" + chunkstatus.getIndex() + chunkstatus + "\u00a7r\n"; + } + +- if (chunkaccess != null) { +- s = s + "Ch: \u00a7" + chunkaccess.getStatus().getIndex() + chunkaccess.getStatus() + "\u00a7r\n"; ++ if (ichunkaccess != null) { ++ s = s + "Ch: \u00a7" + ichunkaccess.getStatus().getIndex() + ichunkaccess.getStatus() + "\u00a7r\n"; + } + +- FullChunkStatus fullchunkstatus = chunkholder.getFullStatus(); ++ FullChunkStatus fullchunkstatus = playerchunk.getFullStatus(); + + s = s + String.valueOf('\u00a7') + fullchunkstatus.ordinal() + fullchunkstatus; + return s + "\u00a7r"; + } + } + +- private CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkHolder chunkholder, int i, IntFunction<ChunkStatus> intfunction) { +- if (i == 0) { +- ChunkStatus chunkstatus = (ChunkStatus) intfunction.apply(0); ++ private CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.Failure>> getChunkRangeFuture(ChunkHolder chunkHolder, int range, IntFunction<ChunkStatus> statusGetter) { ++ if (range == 0) { ++ ChunkStatus chunkstatus = (ChunkStatus) statusGetter.apply(0); + +- return chunkholder.getOrScheduleFuture(chunkstatus, this).thenApply((either) -> { ++ return chunkHolder.getOrScheduleFuture(chunkstatus, this).thenApply((either) -> { + return either.mapLeft(List::of); + }); + } else { +- List<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> list = new ArrayList(); ++ List<CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>>> list = new ArrayList(); + List<ChunkHolder> list1 = new ArrayList(); +- ChunkPos chunkpos = chunkholder.getPos(); +- int j = chunkpos.x; +- int k = chunkpos.z; ++ ChunkPos chunkcoordintpair = chunkHolder.getPos(); ++ int j = chunkcoordintpair.x; ++ int k = chunkcoordintpair.z; + +- for (int l = -i; l <= i; ++l) { +- for (int i1 = -i; i1 <= i; ++i1) { ++ for (int l = -range; l <= range; ++l) { ++ for (int i1 = -range; i1 <= range; ++i1) { + int j1 = Math.max(Math.abs(i1), Math.abs(l)); +- final ChunkPos chunkpos1 = new ChunkPos(j + i1, k + l); +- long k1 = chunkpos1.toLong(); +- ChunkHolder chunkholder1 = this.getUpdatingChunkIfPresent(k1); ++ final ChunkPos chunkcoordintpair1 = new ChunkPos(j + i1, k + l); ++ long k1 = chunkcoordintpair1.toLong(); ++ ChunkHolder playerchunk1 = this.getUpdatingChunkIfPresent(k1); + +- if (chunkholder1 == null) { +- return CompletableFuture.completedFuture(Either.right(new ChunkHolder.ChunkLoadingFailure() { +- @Override ++ if (playerchunk1 == null) { ++ return CompletableFuture.completedFuture(Either.right(new ChunkHolder.Failure() { + public String toString() { +- return "Unloaded " + chunkpos1; ++ return "Unloaded " + chunkcoordintpair1; + } + })); + } + +- ChunkStatus chunkstatus1 = (ChunkStatus) intfunction.apply(j1); +- CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = chunkholder1.getOrScheduleFuture(chunkstatus1, this); ++ ChunkStatus chunkstatus1 = (ChunkStatus) statusGetter.apply(j1); ++ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> completablefuture = playerchunk1.getOrScheduleFuture(chunkstatus1, this); + +- list1.add(chunkholder1); ++ list1.add(playerchunk1); + list.add(completablefuture); + } + } + +- CompletableFuture<List<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> completablefuture1 = Util.sequence(list); +- CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> completablefuture2 = completablefuture1.thenApply((list2) -> { ++ CompletableFuture<List<Either<ChunkAccess, ChunkHolder.Failure>>> completablefuture1 = Util.sequence(list); ++ CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.Failure>> completablefuture2 = completablefuture1.thenApply((list2) -> { + List<ChunkAccess> list3 = Lists.newArrayList(); +- final int l1 = 0; ++ // CraftBukkit start - decompile error ++ int cnt = 0; + +- for (Iterator iterator = list2.iterator(); iterator.hasNext(); ++l1) { +- final Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = (Either) iterator.next(); ++ for (Iterator iterator = list2.iterator(); iterator.hasNext(); ++cnt) { ++ final int l1 = cnt; ++ // CraftBukkit end ++ final Either<ChunkAccess, ChunkHolder.Failure> either = (Either) iterator.next(); + + if (either == null) { + throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a"); +@@ -345,12 +376,11 @@ + Optional<ChunkAccess> optional = either.left(); + + if (optional.isEmpty()) { +- return Either.right(new ChunkHolder.ChunkLoadingFailure() { +- @Override ++ return Either.right(new ChunkHolder.Failure() { + public String toString() { +- ChunkPos chunkpos2 = new ChunkPos(j + l1 % (i * 2 + 1), k + l1 / (i * 2 + 1)); ++ ChunkPos chunkcoordintpair2 = new ChunkPos(j + l1 % (range * 2 + 1), k + l1 / (range * 2 + 1)); + +- return "Unloaded " + chunkpos2 + " " + either.right().get(); ++ return "Unloaded " + chunkcoordintpair2 + " " + either.right().get(); + } + }); + } +@@ -363,24 +393,24 @@ + Iterator iterator = list1.iterator(); + + while (iterator.hasNext()) { +- ChunkHolder chunkholder2 = (ChunkHolder) iterator.next(); ++ ChunkHolder playerchunk2 = (ChunkHolder) iterator.next(); + +- chunkholder2.addSaveDependency("getChunkRangeFuture " + chunkpos + " " + i, completablefuture2); ++ playerchunk2.addSaveDependency("getChunkRangeFuture " + chunkcoordintpair + " " + range, completablefuture2); + } + + return completablefuture2; + } + } + +- public ReportedException debugFuturesAndCreateReportedException(IllegalStateException illegalstateexception, String s) { ++ public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) { + StringBuilder stringbuilder = new StringBuilder(); +- Consumer<ChunkHolder> consumer = (chunkholder) -> { +- chunkholder.getAllFutures().forEach((pair) -> { ++ Consumer<ChunkHolder> consumer = (playerchunk) -> { ++ playerchunk.getAllFutures().forEach((pair) -> { + ChunkStatus chunkstatus = (ChunkStatus) pair.getFirst(); +- CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = (CompletableFuture) pair.getSecond(); ++ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> completablefuture = (CompletableFuture) pair.getSecond(); + + if (completablefuture != null && completablefuture.isDone() && completablefuture.join() == null) { +- stringbuilder.append(chunkholder.getPos()).append(" - status: ").append(chunkstatus).append(" future: ").append(completablefuture).append(System.lineSeparator()); ++ stringbuilder.append(playerchunk.getPos()).append(" - status: ").append(chunkstatus).append(" future: ").append(completablefuture).append(System.lineSeparator()); + } + + }); +@@ -390,16 +420,16 @@ + this.updatingChunkMap.values().forEach(consumer); + stringbuilder.append("Visible:").append(System.lineSeparator()); + this.visibleChunkMap.values().forEach(consumer); +- CrashReport crashreport = CrashReport.forThrowable(illegalstateexception, "Chunk loading"); +- CrashReportCategory crashreportcategory = crashreport.addCategory("Chunk loading"); ++ CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); ++ CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); + +- crashreportcategory.setDetail("Details", (Object) s); +- crashreportcategory.setDetail("Futures", (Object) stringbuilder); ++ crashreportsystemdetails.setDetail("Details", (Object) details); ++ crashreportsystemdetails.setDetail("Futures", (Object) stringbuilder); + return new ReportedException(crashreport); + } + +- public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareEntityTickingChunk(ChunkHolder chunkholder) { +- return this.getChunkRangeFuture(chunkholder, 2, (i) -> { ++ public CompletableFuture<Either<LevelChunk, ChunkHolder.Failure>> prepareEntityTickingChunk(ChunkHolder chunk) { ++ return this.getChunkRangeFuture(chunk, 2, (i) -> { + return ChunkStatus.FULL; + }).thenApplyAsync((either) -> { + return either.mapLeft((list) -> { +@@ -409,40 +439,39 @@ + } + + @Nullable +- ChunkHolder updateChunkScheduling(long i, int j, @Nullable ChunkHolder chunkholder, int k) { +- if (!ChunkLevel.isLoaded(k) && !ChunkLevel.isLoaded(j)) { +- return chunkholder; ++ ChunkHolder updateChunkScheduling(long chunkPos, int j, @Nullable ChunkHolder newLevel, int holder) { ++ if (!ChunkLevel.isLoaded(holder) && !ChunkLevel.isLoaded(j)) { ++ return newLevel; + } else { +- if (chunkholder != null) { +- chunkholder.setTicketLevel(j); ++ if (newLevel != null) { ++ newLevel.setTicketLevel(j); + } + +- if (chunkholder != null) { ++ if (newLevel != null) { + if (!ChunkLevel.isLoaded(j)) { +- this.toDrop.add(i); ++ this.toDrop.add(chunkPos); + } else { +- this.toDrop.remove(i); ++ this.toDrop.remove(chunkPos); + } + } + +- if (ChunkLevel.isLoaded(j) && chunkholder == null) { +- chunkholder = (ChunkHolder) this.pendingUnloads.remove(i); +- if (chunkholder != null) { +- chunkholder.setTicketLevel(j); ++ if (ChunkLevel.isLoaded(j) && newLevel == null) { ++ newLevel = (ChunkHolder) this.pendingUnloads.remove(chunkPos); ++ if (newLevel != null) { ++ newLevel.setTicketLevel(j); + } else { +- chunkholder = new ChunkHolder(new ChunkPos(i), j, this.level, this.lightEngine, this.queueSorter, this); ++ newLevel = new ChunkHolder(new ChunkPos(chunkPos), j, this.level, this.lightEngine, this.queueSorter, this); + } + +- this.updatingChunkMap.put(i, chunkholder); ++ this.updatingChunkMap.put(chunkPos, newLevel); + this.modified = true; + } + +- return chunkholder; ++ return newLevel; + } + } + + @Override +- @Override + public void close() throws IOException { + try { + this.queueSorter.close(); +@@ -453,28 +482,28 @@ + + } + +- protected void saveAllChunks(boolean flag) { +- if (flag) { ++ protected void saveAllChunks(boolean flush) { ++ if (flush) { + List<ChunkHolder> list = this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).toList(); + MutableBoolean mutableboolean = new MutableBoolean(); + + do { + mutableboolean.setFalse(); +- list.stream().map((chunkholder) -> { ++ list.stream().map((playerchunk) -> { + CompletableFuture completablefuture; + + do { +- completablefuture = chunkholder.getChunkToSave(); +- BlockableEventLoop blockableeventloop = this.mainThreadExecutor; ++ completablefuture = playerchunk.getChunkToSave(); ++ BlockableEventLoop iasynctaskhandler = this.mainThreadExecutor; + + Objects.requireNonNull(completablefuture); +- blockableeventloop.managedBlock(completablefuture::isDone); +- } while (completablefuture != chunkholder.getChunkToSave()); ++ iasynctaskhandler.managedBlock(completablefuture::isDone); ++ } while (completablefuture != playerchunk.getChunkToSave()); + + return (ChunkAccess) completablefuture.join(); +- }).filter((chunkaccess) -> { +- return chunkaccess instanceof ImposterProtoChunk || chunkaccess instanceof LevelChunk; +- }).filter(this::save).forEach((chunkaccess) -> { ++ }).filter((ichunkaccess) -> { ++ return ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk; ++ }).filter(this::save).forEach((ichunkaccess) -> { + mutableboolean.setTrue(); + }); + } while (mutableboolean.isTrue()); +@@ -489,35 +518,35 @@ + + } + +- protected void tick(BooleanSupplier booleansupplier) { +- ProfilerFiller profilerfiller = this.level.getProfiler(); ++ protected void tick(BooleanSupplier hasMoreTime) { ++ ProfilerFiller gameprofilerfiller = this.level.getProfiler(); + +- profilerfiller.push("poi"); +- this.poiManager.tick(booleansupplier); +- profilerfiller.popPush("chunk_unload"); ++ gameprofilerfiller.push("poi"); ++ this.poiManager.tick(hasMoreTime); ++ gameprofilerfiller.popPush("chunk_unload"); + if (!this.level.noSave()) { +- this.processUnloads(booleansupplier); ++ this.processUnloads(hasMoreTime); + } + +- profilerfiller.pop(); ++ gameprofilerfiller.pop(); + } + + public boolean hasWork() { + return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); + } + +- private void processUnloads(BooleanSupplier booleansupplier) { ++ private void processUnloads(BooleanSupplier hasMoreTime) { + LongIterator longiterator = this.toDrop.iterator(); + +- for (int i = 0; longiterator.hasNext() && (booleansupplier.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { ++ for (int i = 0; longiterator.hasNext() && (hasMoreTime.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { + long j = longiterator.nextLong(); +- ChunkHolder chunkholder = (ChunkHolder) this.updatingChunkMap.remove(j); ++ ChunkHolder playerchunk = (ChunkHolder) this.updatingChunkMap.remove(j); + +- if (chunkholder != null) { +- this.pendingUnloads.put(j, chunkholder); ++ if (playerchunk != null) { ++ this.pendingUnloads.put(j, playerchunk); + this.modified = true; + ++i; +- this.scheduleUnload(j, chunkholder); ++ this.scheduleUnload(j, playerchunk); + } + } + +@@ -525,7 +554,7 @@ + + Runnable runnable; + +- while ((booleansupplier.getAsBoolean() || k > 0) && (runnable = (Runnable) this.unloadQueue.poll()) != null) { ++ while ((hasMoreTime.getAsBoolean() || k > 0) && (runnable = (Runnable) this.unloadQueue.poll()) != null) { + --k; + runnable.run(); + } +@@ -533,7 +562,7 @@ + int l = 0; + ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); + +- while (l < 20 && booleansupplier.getAsBoolean() && objectiterator.hasNext()) { ++ while (l < 20 && hasMoreTime.getAsBoolean() && objectiterator.hasNext()) { + if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { + ++l; + } +@@ -541,30 +570,30 @@ + + } + +- private void scheduleUnload(long i, ChunkHolder chunkholder) { +- CompletableFuture<ChunkAccess> completablefuture = chunkholder.getChunkToSave(); +- Consumer consumer = (chunkaccess) -> { +- CompletableFuture<ChunkAccess> completablefuture1 = chunkholder.getChunkToSave(); ++ private void scheduleUnload(long chunkPos, ChunkHolder playerchunk) { ++ CompletableFuture<ChunkAccess> completablefuture = playerchunk.getChunkToSave(); ++ Consumer<ChunkAccess> consumer = (ichunkaccess) -> { // CraftBukkit - decompile error ++ CompletableFuture<ChunkAccess> completablefuture1 = playerchunk.getChunkToSave(); + + if (completablefuture1 != completablefuture) { +- this.scheduleUnload(i, chunkholder); ++ this.scheduleUnload(chunkPos, playerchunk); + } else { +- if (this.pendingUnloads.remove(i, chunkholder) && chunkaccess != null) { +- if (chunkaccess instanceof LevelChunk) { +- ((LevelChunk) chunkaccess).setLoaded(false); ++ if (this.pendingUnloads.remove(chunkPos, playerchunk) && ichunkaccess != null) { ++ if (ichunkaccess instanceof LevelChunk) { ++ ((LevelChunk) ichunkaccess).setLoaded(false); + } + +- this.save(chunkaccess); +- if (this.entitiesInLevel.remove(i) && chunkaccess instanceof LevelChunk) { +- LevelChunk levelchunk = (LevelChunk) chunkaccess; ++ this.save(ichunkaccess); ++ if (this.entitiesInLevel.remove(chunkPos) && ichunkaccess instanceof LevelChunk) { ++ LevelChunk chunk = (LevelChunk) ichunkaccess; + +- this.level.unload(levelchunk); ++ this.level.unload(chunk); + } + +- this.lightEngine.updateChunkStatus(chunkaccess.getPos()); ++ this.lightEngine.updateChunkStatus(ichunkaccess.getPos()); + this.lightEngine.tryScheduleUpdate(); +- this.progressListener.onStatusChange(chunkaccess.getPos(), (ChunkStatus) null); +- this.chunkSaveCooldowns.remove(chunkaccess.getPos().toLong()); ++ this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); ++ this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); + } + + } +@@ -574,7 +603,7 @@ + Objects.requireNonNull(this.unloadQueue); + completablefuture.thenAcceptAsync(consumer, queue::add).whenComplete((ovoid, throwable) -> { + if (throwable != null) { +- ChunkMap.LOGGER.error("Failed to save chunk {}", chunkholder.getPos(), throwable); ++ ChunkMap.LOGGER.error("Failed to save chunk {}", playerchunk.getPos(), throwable); + } + + }); +@@ -590,40 +619,40 @@ + } + } + +- public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> schedule(ChunkHolder chunkholder, ChunkStatus chunkstatus) { +- ChunkPos chunkpos = chunkholder.getPos(); ++ public CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> schedule(ChunkHolder holder, ChunkStatus status) { ++ ChunkPos chunkcoordintpair = holder.getPos(); + +- if (chunkstatus == ChunkStatus.EMPTY) { +- return this.scheduleChunkLoad(chunkpos); ++ if (status == ChunkStatus.EMPTY) { ++ return this.scheduleChunkLoad(chunkcoordintpair); + } else { +- if (chunkstatus == ChunkStatus.LIGHT) { +- this.distanceManager.addTicket(TicketType.LIGHT, chunkpos, ChunkLevel.byStatus(ChunkStatus.LIGHT), chunkpos); ++ if (status == ChunkStatus.LIGHT) { ++ this.distanceManager.addTicket(TicketType.LIGHT, chunkcoordintpair, ChunkLevel.byStatus(ChunkStatus.LIGHT), chunkcoordintpair); + } + +- if (!chunkstatus.hasLoadDependencies()) { +- Optional<ChunkAccess> optional = ((Either) chunkholder.getOrScheduleFuture(chunkstatus.getParent(), this).getNow(ChunkHolder.UNLOADED_CHUNK)).left(); ++ if (!status.hasLoadDependencies()) { ++ Optional<ChunkAccess> optional = ((Either) holder.getOrScheduleFuture(status.getParent(), this).getNow(ChunkHolder.UNLOADED_CHUNK)).left(); + +- if (optional.isPresent() && ((ChunkAccess) optional.get()).getStatus().isOrAfter(chunkstatus)) { +- CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = chunkstatus.load(this.level, this.structureTemplateManager, this.lightEngine, (chunkaccess) -> { +- return this.protoChunkToFullChunk(chunkholder); ++ if (optional.isPresent() && ((ChunkAccess) optional.get()).getStatus().isOrAfter(status)) { ++ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> completablefuture = status.load(this.level, this.structureTemplateManager, this.lightEngine, (ichunkaccess) -> { ++ return this.protoChunkToFullChunk(holder); + }, (ChunkAccess) optional.get()); + +- this.progressListener.onStatusChange(chunkpos, chunkstatus); ++ this.progressListener.onStatusChange(chunkcoordintpair, status); + return completablefuture; + } + } + +- return this.scheduleChunkGeneration(chunkholder, chunkstatus); ++ return this.scheduleChunkGeneration(holder, status); + } + } + +- private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> scheduleChunkLoad(ChunkPos chunkpos) { +- return this.readChunk(chunkpos).thenApply((optional) -> { +- return optional.filter((compoundtag) -> { +- boolean flag = isChunkDataValid(compoundtag); ++ private CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> scheduleChunkLoad(ChunkPos chunkPos) { ++ return this.readChunk(chunkPos).thenApply((optional) -> { ++ return optional.filter((nbttagcompound) -> { ++ boolean flag = isChunkDataValid(nbttagcompound); + + if (!flag) { +- ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", chunkpos); ++ ChunkMap.LOGGER.error("Chunk file at {} is missing level data, skipping", chunkPos); + } + + return flag; +@@ -631,193 +660,207 @@ + }).thenApplyAsync((optional) -> { + this.level.getProfiler().incrementCounter("chunkLoad"); + if (optional.isPresent()) { +- ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, chunkpos, (CompoundTag) optional.get()); ++ ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, chunkPos, (CompoundTag) optional.get()); + +- this.markPosition(chunkpos, protochunk.getStatus().getChunkType()); +- return Either.left(protochunk); ++ this.markPosition(chunkPos, protochunk.getStatus().getChunkType()); ++ return Either.<ChunkAccess, ChunkHolder.Failure>left(protochunk); // CraftBukkit - decompile error + } else { +- return Either.left(this.createEmptyChunk(chunkpos)); ++ return Either.<ChunkAccess, ChunkHolder.Failure>left(this.createEmptyChunk(chunkPos)); // CraftBukkit - decompile error + } + }, this.mainThreadExecutor).exceptionallyAsync((throwable) -> { +- return this.handleChunkLoadFailure(throwable, chunkpos); ++ return this.handleChunkLoadFailure(throwable, chunkPos); + }, this.mainThreadExecutor); + } + +- private static boolean isChunkDataValid(CompoundTag compoundtag) { +- return compoundtag.contains("Status", 8); ++ private static boolean isChunkDataValid(CompoundTag tag) { ++ return tag.contains("Status", 8); + } + +- private Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> handleChunkLoadFailure(Throwable throwable, ChunkPos chunkpos) { +- if (throwable instanceof ReportedException) { +- ReportedException reportedexception = (ReportedException) throwable; ++ private Either<ChunkAccess, ChunkHolder.Failure> handleChunkLoadFailure(Throwable exception, ChunkPos chunkPos) { ++ if (exception instanceof ReportedException) { ++ ReportedException reportedexception = (ReportedException) exception; + Throwable throwable1 = reportedexception.getCause(); + + if (!(throwable1 instanceof IOException)) { +- this.markPositionReplaceable(chunkpos); ++ this.markPositionReplaceable(chunkPos); + throw reportedexception; + } + +- ChunkMap.LOGGER.error("Couldn't load chunk {}", chunkpos, throwable1); +- } else if (throwable instanceof IOException) { +- ChunkMap.LOGGER.error("Couldn't load chunk {}", chunkpos, throwable); ++ ChunkMap.LOGGER.error("Couldn't load chunk {}", chunkPos, throwable1); ++ } else if (exception instanceof IOException) { ++ ChunkMap.LOGGER.error("Couldn't load chunk {}", chunkPos, exception); + } + +- return Either.left(this.createEmptyChunk(chunkpos)); ++ return Either.left(this.createEmptyChunk(chunkPos)); + } + +- private ChunkAccess createEmptyChunk(ChunkPos chunkpos) { +- this.markPositionReplaceable(chunkpos); +- return new ProtoChunk(chunkpos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData) null); ++ private ChunkAccess createEmptyChunk(ChunkPos chunkPos) { ++ this.markPositionReplaceable(chunkPos); ++ return new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData) null); + } + +- private void markPositionReplaceable(ChunkPos chunkpos) { +- this.chunkTypeCache.put(chunkpos.toLong(), (byte) -1); ++ private void markPositionReplaceable(ChunkPos chunkPos) { ++ this.chunkTypeCache.put(chunkPos.toLong(), (byte) -1); + } + +- private byte markPosition(ChunkPos chunkpos, ChunkStatus.ChunkType chunkstatus_chunktype) { +- return this.chunkTypeCache.put(chunkpos.toLong(), (byte) (chunkstatus_chunktype == ChunkStatus.ChunkType.PROTOCHUNK ? -1 : 1)); ++ private byte markPosition(ChunkPos chunkPos, ChunkStatus.Type chunkType) { ++ return this.chunkTypeCache.put(chunkPos.toLong(), (byte) (chunkType == ChunkStatus.Type.PROTOCHUNK ? -1 : 1)); + } + +- private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> scheduleChunkGeneration(ChunkHolder chunkholder, ChunkStatus chunkstatus) { +- ChunkPos chunkpos = chunkholder.getPos(); +- CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(chunkholder, chunkstatus.getRange(), (i) -> { +- return this.getDependencyStatus(chunkstatus, i); ++ private CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> scheduleChunkGeneration(ChunkHolder chunkHolder, ChunkStatus chunkStatus) { ++ ChunkPos chunkcoordintpair = chunkHolder.getPos(); ++ CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.Failure>> completablefuture = this.getChunkRangeFuture(chunkHolder, chunkStatus.getRange(), (i) -> { ++ return this.getDependencyStatus(chunkStatus, i); + }); + + this.level.getProfiler().incrementCounter(() -> { +- return "chunkGenerate " + chunkstatus; ++ return "chunkGenerate " + chunkStatus; + }); + Executor executor = (runnable) -> { +- this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkholder, runnable)); ++ this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkHolder, runnable)); + }; + + return completablefuture.thenComposeAsync((either) -> { + return (CompletionStage) either.map((list) -> { + try { +- ChunkAccess chunkaccess = (ChunkAccess) list.get(list.size() / 2); ++ ChunkAccess ichunkaccess = (ChunkAccess) list.get(list.size() / 2); + CompletableFuture completablefuture1; + +- if (chunkaccess.getStatus().isOrAfter(chunkstatus)) { +- completablefuture1 = chunkstatus.load(this.level, this.structureTemplateManager, this.lightEngine, (chunkaccess1) -> { +- return this.protoChunkToFullChunk(chunkholder); +- }, chunkaccess); ++ if (ichunkaccess.getStatus().isOrAfter(chunkStatus)) { ++ completablefuture1 = chunkStatus.load(this.level, this.structureTemplateManager, this.lightEngine, (ichunkaccess1) -> { ++ return this.protoChunkToFullChunk(chunkHolder); ++ }, ichunkaccess); + } else { +- completablefuture1 = chunkstatus.generate(executor, this.level, this.generator, this.structureTemplateManager, this.lightEngine, (chunkaccess1) -> { +- return this.protoChunkToFullChunk(chunkholder); ++ completablefuture1 = chunkStatus.generate(executor, this.level, this.generator, this.structureTemplateManager, this.lightEngine, (ichunkaccess1) -> { ++ return this.protoChunkToFullChunk(chunkHolder); + }, list); + } + +- this.progressListener.onStatusChange(chunkpos, chunkstatus); ++ this.progressListener.onStatusChange(chunkcoordintpair, chunkStatus); + return completablefuture1; + } catch (Exception exception) { + exception.getStackTrace(); + CrashReport crashreport = CrashReport.forThrowable(exception, "Exception generating new chunk"); +- CrashReportCategory crashreportcategory = crashreport.addCategory("Chunk to be generated"); ++ CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk to be generated"); + +- crashreportcategory.setDetail("Location", (Object) String.format(Locale.ROOT, "%d,%d", chunkpos.x, chunkpos.z)); +- crashreportcategory.setDetail("Position hash", (Object) ChunkPos.asLong(chunkpos.x, chunkpos.z)); +- crashreportcategory.setDetail("Generator", (Object) this.generator); ++ crashreportsystemdetails.setDetail("Location", (Object) String.format(Locale.ROOT, "%d,%d", chunkcoordintpair.x, chunkcoordintpair.z)); ++ crashreportsystemdetails.setDetail("Position hash", (Object) ChunkPos.asLong(chunkcoordintpair.x, chunkcoordintpair.z)); ++ crashreportsystemdetails.setDetail("Generator", (Object) this.generator); + this.mainThreadExecutor.execute(() -> { + throw new ReportedException(crashreport); + }); + throw new ReportedException(crashreport); + } +- }, (chunkholder_chunkloadingfailure) -> { +- this.releaseLightTicket(chunkpos); +- return CompletableFuture.completedFuture(Either.right(chunkholder_chunkloadingfailure)); ++ }, (playerchunk_failure) -> { ++ this.releaseLightTicket(chunkcoordintpair); ++ return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); + }); + }, executor); + } + +- protected void releaseLightTicket(ChunkPos chunkpos) { ++ protected void releaseLightTicket(ChunkPos chunkPos) { + this.mainThreadExecutor.tell(Util.name(() -> { +- this.distanceManager.removeTicket(TicketType.LIGHT, chunkpos, ChunkLevel.byStatus(ChunkStatus.LIGHT), chunkpos); ++ this.distanceManager.removeTicket(TicketType.LIGHT, chunkPos, ChunkLevel.byStatus(ChunkStatus.LIGHT), chunkPos); + }, () -> { +- return "release light ticket " + chunkpos; ++ return "release light ticket " + chunkPos; + })); + } + +- private ChunkStatus getDependencyStatus(ChunkStatus chunkstatus, int i) { ++ private ChunkStatus getDependencyStatus(ChunkStatus chunkStatus, int i) { + ChunkStatus chunkstatus1; + + if (i == 0) { +- chunkstatus1 = chunkstatus.getParent(); ++ chunkstatus1 = chunkStatus.getParent(); + } else { +- chunkstatus1 = ChunkStatus.getStatusAroundFullChunk(ChunkStatus.getDistance(chunkstatus) + i); ++ chunkstatus1 = ChunkStatus.getStatusAroundFullChunk(ChunkStatus.getDistance(chunkStatus) + i); + } + + return chunkstatus1; + } + +- private static void postLoadProtoChunk(ServerLevel serverlevel, List<CompoundTag> list) { +- if (!list.isEmpty()) { +- serverlevel.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(list, serverlevel)); ++ private static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> tags) { ++ if (!tags.isEmpty()) { ++ // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities ++ level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(tags, level).filter((entity) -> { ++ boolean needsRemoval = false; ++ net.minecraft.server.dedicated.DedicatedServer server = level.getCraftServer().getServer(); ++ if (!server.areNpcsEnabled() && entity instanceof net.minecraft.world.entity.npc.NPC) { ++ entity.discard(); ++ needsRemoval = true; ++ } ++ if (!server.isSpawningAnimals() && (entity instanceof net.minecraft.world.entity.animal.Animal || entity instanceof net.minecraft.world.entity.animal.WaterAnimal)) { ++ entity.discard(); ++ needsRemoval = true; ++ } ++ return !needsRemoval; ++ })); ++ // CraftBukkit end + } + + } + +- private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> protoChunkToFullChunk(ChunkHolder chunkholder) { +- CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = chunkholder.getFutureIfPresentUnchecked(ChunkStatus.FULL.getParent()); ++ private CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> protoChunkToFullChunk(ChunkHolder holder) { ++ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> completablefuture = holder.getFutureIfPresentUnchecked(ChunkStatus.FULL.getParent()); + + return completablefuture.thenApplyAsync((either) -> { +- ChunkStatus chunkstatus = ChunkLevel.generationStatus(chunkholder.getTicketLevel()); ++ ChunkStatus chunkstatus = ChunkLevel.generationStatus(holder.getTicketLevel()); + +- return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((chunkaccess) -> { +- ChunkPos chunkpos = chunkholder.getPos(); +- ProtoChunk protochunk = (ProtoChunk) chunkaccess; +- LevelChunk levelchunk; ++ return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((ichunkaccess) -> { ++ ChunkPos chunkcoordintpair = holder.getPos(); ++ ProtoChunk protochunk = (ProtoChunk) ichunkaccess; ++ LevelChunk chunk; + + if (protochunk instanceof ImposterProtoChunk) { +- levelchunk = ((ImposterProtoChunk) protochunk).getWrapped(); ++ chunk = ((ImposterProtoChunk) protochunk).getWrapped(); + } else { +- levelchunk = new LevelChunk(this.level, protochunk, (levelchunk1) -> { ++ chunk = new LevelChunk(this.level, protochunk, (chunk1) -> { + postLoadProtoChunk(this.level, protochunk.getEntities()); + }); +- chunkholder.replaceProtoChunk(new ImposterProtoChunk(levelchunk, false)); ++ holder.replaceProtoChunk(new ImposterProtoChunk(chunk, false)); + } + +- levelchunk.setFullStatus(() -> { +- return ChunkLevel.fullStatus(chunkholder.getTicketLevel()); ++ chunk.setFullStatus(() -> { ++ return ChunkLevel.fullStatus(holder.getTicketLevel()); + }); +- levelchunk.runPostLoad(); +- if (this.entitiesInLevel.add(chunkpos.toLong())) { +- levelchunk.setLoaded(true); +- levelchunk.registerAllBlockEntitiesAfterLevelLoad(); +- levelchunk.registerTickContainerInLevel(this.level); ++ chunk.runPostLoad(); ++ if (this.entitiesInLevel.add(chunkcoordintpair.toLong())) { ++ chunk.setLoaded(true); ++ chunk.registerAllBlockEntitiesAfterLevelLoad(); ++ chunk.registerTickContainerInLevel(this.level); + } + +- return levelchunk; ++ return chunk; + }); + }, (runnable) -> { +- ProcessorHandle processorhandle = this.mainThreadMailbox; +- long i = chunkholder.getPos().toLong(); ++ ProcessorHandle mailbox = this.mainThreadMailbox; ++ long i = holder.getPos().toLong(); + +- Objects.requireNonNull(chunkholder); +- processorhandle.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, chunkholder::getTicketLevel)); ++ Objects.requireNonNull(holder); ++ mailbox.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, holder::getTicketLevel)); + }); + } + +- public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareTickingChunk(ChunkHolder chunkholder) { +- CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(chunkholder, 1, (i) -> { ++ public CompletableFuture<Either<LevelChunk, ChunkHolder.Failure>> prepareTickingChunk(ChunkHolder holder) { ++ CompletableFuture<Either<List<ChunkAccess>, ChunkHolder.Failure>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { + return ChunkStatus.FULL; + }); +- CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> completablefuture1 = completablefuture.thenApplyAsync((either) -> { ++ CompletableFuture<Either<LevelChunk, ChunkHolder.Failure>> completablefuture1 = completablefuture.thenApplyAsync((either) -> { + return either.mapLeft((list) -> { + return (LevelChunk) list.get(list.size() / 2); + }); + }, (runnable) -> { +- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkholder, runnable)); ++ this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); + }).thenApplyAsync((either) -> { +- return either.ifLeft((levelchunk) -> { +- levelchunk.postProcessGeneration(); +- this.level.startTickingChunk(levelchunk); +- CompletableFuture<?> completablefuture2 = chunkholder.getChunkSendSyncFuture(); ++ return either.ifLeft((chunk) -> { ++ chunk.postProcessGeneration(); ++ this.level.startTickingChunk(chunk); ++ CompletableFuture<?> completablefuture2 = holder.getChunkSendSyncFuture(); + + if (completablefuture2.isDone()) { +- this.onChunkReadyToSend(levelchunk); ++ this.onChunkReadyToSend(chunk); + } else { + completablefuture2.thenAcceptAsync((object) -> { +- this.onChunkReadyToSend(levelchunk); ++ this.onChunkReadyToSend(chunk); + }, this.mainThreadExecutor); + } + +@@ -831,27 +874,27 @@ + return completablefuture1; + } + +- private void onChunkReadyToSend(LevelChunk levelchunk) { +- ChunkPos chunkpos = levelchunk.getPos(); ++ private void onChunkReadyToSend(LevelChunk chunk) { ++ ChunkPos chunkcoordintpair = chunk.getPos(); + Iterator iterator = this.playerMap.getAllPlayers().iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- if (serverplayer.getChunkTrackingView().contains(chunkpos)) { +- markChunkPendingToSend(serverplayer, levelchunk); ++ if (entityplayer.getChunkTrackingView().contains(chunkcoordintpair)) { ++ markChunkPendingToSend(entityplayer, chunk); + } + } + + } + +- public CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> prepareAccessibleChunk(ChunkHolder chunkholder) { +- return this.getChunkRangeFuture(chunkholder, 1, ChunkStatus::getStatusAroundFullChunk).thenApplyAsync((either) -> { ++ public CompletableFuture<Either<LevelChunk, ChunkHolder.Failure>> prepareAccessibleChunk(ChunkHolder holder) { ++ return this.getChunkRangeFuture(holder, 1, ChunkStatus::getStatusAroundFullChunk).thenApplyAsync((either) -> { + return either.mapLeft((list) -> { + return (LevelChunk) list.get(list.size() / 2); + }); + }, (runnable) -> { +- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkholder, runnable)); ++ this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); + }); + } + +@@ -859,25 +902,25 @@ + return this.tickingGenerated.get(); + } + +- private boolean saveChunkIfNeeded(ChunkHolder chunkholder) { +- if (!chunkholder.wasAccessibleSinceLastSave()) { ++ private boolean saveChunkIfNeeded(ChunkHolder holder) { ++ if (!holder.wasAccessibleSinceLastSave()) { + return false; + } else { +- ChunkAccess chunkaccess = (ChunkAccess) chunkholder.getChunkToSave().getNow((Object) null); ++ ChunkAccess ichunkaccess = (ChunkAccess) holder.getChunkToSave().getNow(null); // CraftBukkit - decompile error + +- if (!(chunkaccess instanceof ImposterProtoChunk) && !(chunkaccess instanceof LevelChunk)) { ++ if (!(ichunkaccess instanceof ImposterProtoChunk) && !(ichunkaccess instanceof LevelChunk)) { + return false; + } else { +- long i = chunkaccess.getPos().toLong(); ++ long i = ichunkaccess.getPos().toLong(); + long j = this.chunkSaveCooldowns.getOrDefault(i, -1L); + long k = System.currentTimeMillis(); + + if (k < j) { + return false; + } else { +- boolean flag = this.save(chunkaccess); ++ boolean flag = this.save(ichunkaccess); + +- chunkholder.refreshAccessibility(); ++ holder.refreshAccessibility(); + if (flag) { + this.chunkSaveCooldowns.put(i, k + 10000L); + } +@@ -888,63 +931,63 @@ + } + } + +- private boolean save(ChunkAccess chunkaccess) { +- this.poiManager.flush(chunkaccess.getPos()); +- if (!chunkaccess.isUnsaved()) { ++ public boolean save(ChunkAccess chunk) { ++ this.poiManager.flush(chunk.getPos()); ++ if (!chunk.isUnsaved()) { + return false; + } else { +- chunkaccess.setUnsaved(false); +- ChunkPos chunkpos = chunkaccess.getPos(); ++ chunk.setUnsaved(false); ++ ChunkPos chunkcoordintpair = chunk.getPos(); + + try { +- ChunkStatus chunkstatus = chunkaccess.getStatus(); ++ ChunkStatus chunkstatus = chunk.getStatus(); + +- if (chunkstatus.getChunkType() != ChunkStatus.ChunkType.LEVELCHUNK) { +- if (this.isExistingChunkFull(chunkpos)) { ++ if (chunkstatus.getChunkType() != ChunkStatus.Type.LEVELCHUNK) { ++ if (this.isExistingChunkFull(chunkcoordintpair)) { + return false; + } + +- if (chunkstatus == ChunkStatus.EMPTY && chunkaccess.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { ++ if (chunkstatus == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { + return false; + } + } + + this.level.getProfiler().incrementCounter("chunkSave"); +- CompoundTag compoundtag = ChunkSerializer.write(this.level, chunkaccess); ++ CompoundTag nbttagcompound = ChunkSerializer.write(this.level, chunk); + +- this.write(chunkpos, compoundtag); +- this.markPosition(chunkpos, chunkstatus.getChunkType()); ++ this.write(chunkcoordintpair, nbttagcompound); ++ this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); + return true; + } catch (Exception exception) { +- ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkpos.x, chunkpos.z, exception}); ++ ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception}); + return false; + } + } + } + +- private boolean isExistingChunkFull(ChunkPos chunkpos) { +- byte b0 = this.chunkTypeCache.get(chunkpos.toLong()); ++ private boolean isExistingChunkFull(ChunkPos chunkPos) { ++ byte b0 = this.chunkTypeCache.get(chunkPos.toLong()); + + if (b0 != 0) { + return b0 == 1; + } else { +- CompoundTag compoundtag; ++ CompoundTag nbttagcompound; + + try { +- compoundtag = (CompoundTag) ((Optional) this.readChunk(chunkpos).join()).orElse((Object) null); +- if (compoundtag == null) { +- this.markPositionReplaceable(chunkpos); ++ nbttagcompound = (CompoundTag) ((Optional) this.readChunk(chunkPos).join()).orElse((Object) null); ++ if (nbttagcompound == null) { ++ this.markPositionReplaceable(chunkPos); + return false; + } + } catch (Exception exception) { +- ChunkMap.LOGGER.error("Failed to read chunk {}", chunkpos, exception); +- this.markPositionReplaceable(chunkpos); ++ ChunkMap.LOGGER.error("Failed to read chunk {}", chunkPos, exception); ++ this.markPositionReplaceable(chunkPos); + return false; + } + +- ChunkStatus.ChunkType chunkstatus_chunktype = ChunkSerializer.getChunkTypeFromTag(compoundtag); ++ ChunkStatus.Type chunkstatus_type = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); + +- return this.markPosition(chunkpos, chunkstatus_chunktype) == 1; ++ return this.markPosition(chunkPos, chunkstatus_type) == 1; + } + } + +@@ -957,47 +1000,47 @@ + Iterator iterator = this.playerMap.getAllPlayers().iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- this.updateChunkTracking(serverplayer); ++ this.updateChunkTracking(entityplayer); + } + } + + } + +- int getPlayerViewDistance(ServerPlayer serverplayer) { +- return Mth.clamp(serverplayer.requestedViewDistance(), 2, this.serverViewDistance); ++ int getPlayerViewDistance(ServerPlayer entityplayer) { ++ return Mth.clamp(entityplayer.requestedViewDistance(), 2, this.serverViewDistance); + } + +- private void markChunkPendingToSend(ServerPlayer serverplayer, ChunkPos chunkpos) { +- LevelChunk levelchunk = this.getChunkToSend(chunkpos.toLong()); ++ private void markChunkPendingToSend(ServerPlayer entityplayer, ChunkPos chunkcoordintpair) { ++ LevelChunk chunk = this.getChunkToSend(chunkcoordintpair.toLong()); + +- if (levelchunk != null) { +- markChunkPendingToSend(serverplayer, levelchunk); ++ if (chunk != null) { ++ markChunkPendingToSend(entityplayer, chunk); + } + + } + +- private static void markChunkPendingToSend(ServerPlayer serverplayer, LevelChunk levelchunk) { +- serverplayer.connection.chunkSender.markChunkPendingToSend(levelchunk); ++ private static void markChunkPendingToSend(ServerPlayer entityplayer, LevelChunk chunk) { ++ entityplayer.connection.chunkSender.markChunkPendingToSend(chunk); + } + +- private static void dropChunk(ServerPlayer serverplayer, ChunkPos chunkpos) { +- serverplayer.connection.chunkSender.dropChunk(serverplayer, chunkpos); ++ private static void dropChunk(ServerPlayer entityplayer, ChunkPos chunkcoordintpair) { ++ entityplayer.connection.chunkSender.dropChunk(entityplayer, chunkcoordintpair); + } + + @Nullable + public LevelChunk getChunkToSend(long i) { +- ChunkHolder chunkholder = this.getVisibleChunkIfPresent(i); ++ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(i); + +- return chunkholder == null ? null : chunkholder.getChunkToSend(); ++ return playerchunk == null ? null : playerchunk.getChunkToSend(); + } + + public int size() { + return this.visibleChunkMap.size(); + } + +- public net.minecraft.server.level.DistanceManager getDistanceManager() { ++ public DistanceManager getDistanceManager() { + return this.distanceManager; + } + +@@ -1006,38 +1049,39 @@ + } + + void dumpChunks(Writer writer) throws IOException { +- CsvOutput csvoutput = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); ++ CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); + TickingTracker tickingtracker = this.distanceManager.tickingTracker(); + ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); + + while (objectbidirectionaliterator.hasNext()) { + Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next(); + long i = entry.getLongKey(); +- ChunkPos chunkpos = new ChunkPos(i); +- ChunkHolder chunkholder = (ChunkHolder) entry.getValue(); +- Optional<ChunkAccess> optional = Optional.ofNullable(chunkholder.getLastAvailable()); +- Optional<LevelChunk> optional1 = optional.flatMap((chunkaccess) -> { +- return chunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) chunkaccess) : Optional.empty(); ++ ChunkPos chunkcoordintpair = new ChunkPos(i); ++ ChunkHolder playerchunk = (ChunkHolder) entry.getValue(); ++ Optional<ChunkAccess> optional = Optional.ofNullable(playerchunk.getLastAvailable()); ++ Optional<LevelChunk> optional1 = optional.flatMap((ichunkaccess) -> { ++ return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty(); + }); + +- csvoutput.writeRow(chunkpos.x, chunkpos.z, chunkholder.getTicketLevel(), optional.isPresent(), optional.map(ChunkAccess::getStatus).orElse((Object) null), optional1.map(LevelChunk::getFullStatus).orElse((Object) null), printFuture(chunkholder.getFullChunkFuture()), printFuture(chunkholder.getTickingChunkFuture()), printFuture(chunkholder.getEntityTickingChunkFuture()), this.distanceManager.getTicketDebugString(i), this.anyPlayerCloseEnoughForSpawning(chunkpos), optional1.map((levelchunk) -> { +- return levelchunk.getBlockEntities().size(); +- }).orElse(0), tickingtracker.getTicketDebugString(i), tickingtracker.getLevel(i), optional1.map((levelchunk) -> { +- return levelchunk.getBlockTicks().count(); +- }).orElse(0), optional1.map((levelchunk) -> { +- return levelchunk.getFluidTicks().count(); ++ // CraftBukkit - decompile error ++ csvwriter.writeRow(chunkcoordintpair.x, chunkcoordintpair.z, playerchunk.getTicketLevel(), optional.isPresent(), optional.map(ChunkAccess::getStatus).orElse(null), optional1.map(LevelChunk::getFullStatus).orElse(null), printFuture(playerchunk.getFullChunkFuture()), printFuture(playerchunk.getTickingChunkFuture()), printFuture(playerchunk.getEntityTickingChunkFuture()), this.distanceManager.getTicketDebugString(i), this.anyPlayerCloseEnoughForSpawning(chunkcoordintpair), optional1.map((chunk) -> { ++ return chunk.getBlockEntities().size(); ++ }).orElse(0), tickingtracker.getTicketDebugString(i), tickingtracker.getLevel(i), optional1.map((chunk) -> { ++ return chunk.getBlockTicks().count(); ++ }).orElse(0), optional1.map((chunk) -> { ++ return chunk.getFluidTicks().count(); + }).orElse(0)); + } + + } + +- private static String printFuture(CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> completablefuture) { ++ private static String printFuture(CompletableFuture<Either<LevelChunk, ChunkHolder.Failure>> future) { + try { +- Either<LevelChunk, ChunkHolder.ChunkLoadingFailure> either = (Either) completablefuture.getNow((Object) null); ++ Either<LevelChunk, ChunkHolder.Failure> either = (Either) future.getNow(null); // CraftBukkit - decompile error + +- return either != null ? (String) either.map((levelchunk) -> { ++ return either != null ? (String) either.map((chunk) -> { + return "done"; +- }, (chunkholder_chunkloadingfailure) -> { ++ }, (playerchunk_failure) -> { + return "unloaded"; + }) : "not completed"; + } catch (CompletionException completionexception) { +@@ -1047,38 +1091,40 @@ + } + } + +- private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkpos) { +- return this.read(chunkpos).thenApplyAsync((optional) -> { +- return optional.map(this::upgradeChunkTag); ++ private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos pos) { ++ return this.read(pos).thenApplyAsync((optional) -> { ++ return optional.map((nbttagcompound) -> upgradeChunkTag(nbttagcompound, pos)); // CraftBukkit + }, Util.backgroundExecutor()); + } + +- private CompoundTag upgradeChunkTag(CompoundTag compoundtag) { +- return this.upgradeChunkTag(this.level.dimension(), this.overworldDataStorage, compoundtag, this.generator.getTypeNameForDataFixer()); ++ // CraftBukkit start ++ private CompoundTag upgradeChunkTag(CompoundTag nbttagcompound, ChunkPos chunkcoordintpair) { ++ return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator.getTypeNameForDataFixer(), chunkcoordintpair, level); ++ // CraftBukkit end + } + +- boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkpos) { +- if (!this.distanceManager.hasPlayersNearby(chunkpos.toLong())) { ++ boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkPos) { ++ if (!this.distanceManager.hasPlayersNearby(chunkPos.toLong())) { + return false; + } else { + Iterator iterator = this.playerMap.getAllPlayers().iterator(); + +- ServerPlayer serverplayer; ++ ServerPlayer entityplayer; + + do { + if (!iterator.hasNext()) { + return false; + } + +- serverplayer = (ServerPlayer) iterator.next(); +- } while (!this.playerIsCloseEnoughForSpawning(serverplayer, chunkpos)); ++ entityplayer = (ServerPlayer) iterator.next(); ++ } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkPos)); + + return true; + } + } + +- public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos chunkpos) { +- long i = chunkpos.toLong(); ++ public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos chunkPos) { ++ long i = chunkPos.toLong(); + + if (!this.distanceManager.hasPlayersNearby(i)) { + return List.of(); +@@ -1087,10 +1133,10 @@ + Iterator iterator = this.playerMap.getAllPlayers().iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- if (this.playerIsCloseEnoughForSpawning(serverplayer, chunkpos)) { +- builder.add(serverplayer); ++ if (this.playerIsCloseEnoughForSpawning(entityplayer, chunkPos)) { ++ builder.add(entityplayer); + } + } + +@@ -1098,152 +1144,151 @@ + } + } + +- private boolean playerIsCloseEnoughForSpawning(ServerPlayer serverplayer, ChunkPos chunkpos) { +- if (serverplayer.isSpectator()) { ++ private boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos chunkPos) { ++ if (player.isSpectator()) { + return false; + } else { +- double d0 = euclideanDistanceSquared(chunkpos, serverplayer); ++ double d0 = euclideanDistanceSquared(chunkPos, player); + + return d0 < 16384.0D; + } + } + +- private boolean skipPlayer(ServerPlayer serverplayer) { +- return serverplayer.isSpectator() && !this.level.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS); ++ private boolean skipPlayer(ServerPlayer player) { ++ return player.isSpectator() && !this.level.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS); + } + +- void updatePlayerStatus(ServerPlayer serverplayer, boolean flag) { +- boolean flag1 = this.skipPlayer(serverplayer); +- boolean flag2 = this.playerMap.ignoredOrUnknown(serverplayer); ++ void updatePlayerStatus(ServerPlayer player, boolean track) { ++ boolean flag1 = this.skipPlayer(player); ++ boolean flag2 = this.playerMap.ignoredOrUnknown(player); + +- if (flag) { +- this.playerMap.addPlayer(serverplayer, flag1); +- this.updatePlayerPos(serverplayer); ++ if (track) { ++ this.playerMap.addPlayer(player, flag1); ++ this.updatePlayerPos(player); + if (!flag1) { +- this.distanceManager.addPlayer(SectionPos.of((EntityAccess) serverplayer), serverplayer); ++ this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); + } + +- serverplayer.setChunkTrackingView(ChunkTrackingView.EMPTY); +- this.updateChunkTracking(serverplayer); ++ player.setChunkTrackingView(ChunkTrackingView.EMPTY); ++ this.updateChunkTracking(player); + } else { +- SectionPos sectionpos = serverplayer.getLastSectionPos(); ++ SectionPos sectionposition = player.getLastSectionPos(); + +- this.playerMap.removePlayer(serverplayer); ++ this.playerMap.removePlayer(player); + if (!flag2) { +- this.distanceManager.removePlayer(sectionpos, serverplayer); ++ this.distanceManager.removePlayer(sectionposition, player); + } + +- this.applyChunkTrackingView(serverplayer, ChunkTrackingView.EMPTY); ++ this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY); + } + + } + +- private void updatePlayerPos(ServerPlayer serverplayer) { +- SectionPos sectionpos = SectionPos.of((EntityAccess) serverplayer); ++ private void updatePlayerPos(ServerPlayer entityplayer) { ++ SectionPos sectionposition = SectionPos.of((EntityAccess) entityplayer); + +- serverplayer.setLastSectionPos(sectionpos); ++ entityplayer.setLastSectionPos(sectionposition); + } + +- public void move(ServerPlayer serverplayer) { ++ public void move(ServerPlayer player) { + ObjectIterator objectiterator = this.entityMap.values().iterator(); + + while (objectiterator.hasNext()) { +- ChunkMap.TrackedEntity chunkmap_trackedentity = (ChunkMap.TrackedEntity) objectiterator.next(); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); + +- if (chunkmap_trackedentity.entity == serverplayer) { +- chunkmap_trackedentity.updatePlayers(this.level.players()); ++ if (playerchunkmap_entitytracker.entity == player) { ++ playerchunkmap_entitytracker.updatePlayers(this.level.players()); + } else { +- chunkmap_trackedentity.updatePlayer(serverplayer); ++ playerchunkmap_entitytracker.updatePlayer(player); + } + } + +- SectionPos sectionpos = serverplayer.getLastSectionPos(); +- SectionPos sectionpos1 = SectionPos.of((EntityAccess) serverplayer); +- boolean flag = this.playerMap.ignored(serverplayer); +- boolean flag1 = this.skipPlayer(serverplayer); +- boolean flag2 = sectionpos.asLong() != sectionpos1.asLong(); ++ SectionPos sectionposition = player.getLastSectionPos(); ++ SectionPos sectionposition1 = SectionPos.of((EntityAccess) player); ++ boolean flag = this.playerMap.ignored(player); ++ boolean flag1 = this.skipPlayer(player); ++ boolean flag2 = sectionposition.asLong() != sectionposition1.asLong(); + + if (flag2 || flag != flag1) { +- this.updatePlayerPos(serverplayer); ++ this.updatePlayerPos(player); + if (!flag) { +- this.distanceManager.removePlayer(sectionpos, serverplayer); ++ this.distanceManager.removePlayer(sectionposition, player); + } + + if (!flag1) { +- this.distanceManager.addPlayer(sectionpos1, serverplayer); ++ this.distanceManager.addPlayer(sectionposition1, player); + } + + if (!flag && flag1) { +- this.playerMap.ignorePlayer(serverplayer); ++ this.playerMap.ignorePlayer(player); + } + + if (flag && !flag1) { +- this.playerMap.unIgnorePlayer(serverplayer); ++ this.playerMap.unIgnorePlayer(player); + } + +- this.updateChunkTracking(serverplayer); ++ this.updateChunkTracking(player); + } + + } + +- private void updateChunkTracking(ServerPlayer serverplayer) { +- ChunkPos chunkpos = serverplayer.chunkPosition(); +- int i = this.getPlayerViewDistance(serverplayer); +- ChunkTrackingView chunktrackingview = serverplayer.getChunkTrackingView(); ++ private void updateChunkTracking(ServerPlayer entityplayer) { ++ ChunkPos chunkcoordintpair = entityplayer.chunkPosition(); ++ int i = this.getPlayerViewDistance(entityplayer); ++ ChunkTrackingView chunktrackingview = entityplayer.getChunkTrackingView(); + +- if (chunktrackingview instanceof ChunkTrackingView.Positioned) { +- ChunkTrackingView.Positioned chunktrackingview_positioned = (ChunkTrackingView.Positioned) chunktrackingview; ++ if (chunktrackingview instanceof ChunkTrackingView.a) { ++ ChunkTrackingView.a chunktrackingview_a = (ChunkTrackingView.a) chunktrackingview; + +- if (chunktrackingview_positioned.center().equals(chunkpos) && chunktrackingview_positioned.viewDistance() == i) { ++ if (chunktrackingview_a.center().equals(chunkcoordintpair) && chunktrackingview_a.viewDistance() == i) { + return; + } + } + +- this.applyChunkTrackingView(serverplayer, ChunkTrackingView.of(chunkpos, i)); ++ this.applyChunkTrackingView(entityplayer, ChunkTrackingView.of(chunkcoordintpair, i)); + } + +- private void applyChunkTrackingView(ServerPlayer serverplayer, ChunkTrackingView chunktrackingview) { +- if (serverplayer.level() == this.level) { +- ChunkTrackingView chunktrackingview1 = serverplayer.getChunkTrackingView(); ++ private void applyChunkTrackingView(ServerPlayer entityplayer, ChunkTrackingView chunktrackingview) { ++ if (entityplayer.level() == this.level) { ++ ChunkTrackingView chunktrackingview1 = entityplayer.getChunkTrackingView(); + +- if (chunktrackingview instanceof ChunkTrackingView.Positioned) { ++ if (chunktrackingview instanceof ChunkTrackingView.a) { + label15: + { +- ChunkTrackingView.Positioned chunktrackingview_positioned = (ChunkTrackingView.Positioned) chunktrackingview; ++ ChunkTrackingView.a chunktrackingview_a = (ChunkTrackingView.a) chunktrackingview; + +- if (chunktrackingview1 instanceof ChunkTrackingView.Positioned) { +- ChunkTrackingView.Positioned chunktrackingview_positioned1 = (ChunkTrackingView.Positioned) chunktrackingview1; ++ if (chunktrackingview1 instanceof ChunkTrackingView.a) { ++ ChunkTrackingView.a chunktrackingview_a1 = (ChunkTrackingView.a) chunktrackingview1; + +- if (chunktrackingview_positioned1.center().equals(chunktrackingview_positioned.center())) { ++ if (chunktrackingview_a1.center().equals(chunktrackingview_a.center())) { + break label15; + } + } + +- serverplayer.connection.send(new ClientboundSetChunkCacheCenterPacket(chunktrackingview_positioned.center().x, chunktrackingview_positioned.center().z)); ++ entityplayer.connection.send(new ClientboundSetChunkCacheCenterPacket(chunktrackingview_a.center().x, chunktrackingview_a.center().z)); + } + } + +- ChunkTrackingView.difference(chunktrackingview1, chunktrackingview, (chunkpos) -> { +- this.markChunkPendingToSend(serverplayer, chunkpos); +- }, (chunkpos) -> { +- dropChunk(serverplayer, chunkpos); ++ ChunkTrackingView.difference(chunktrackingview1, chunktrackingview, (chunkcoordintpair) -> { ++ this.markChunkPendingToSend(entityplayer, chunkcoordintpair); ++ }, (chunkcoordintpair) -> { ++ dropChunk(entityplayer, chunkcoordintpair); + }); +- serverplayer.setChunkTrackingView(chunktrackingview); ++ entityplayer.setChunkTrackingView(chunktrackingview); + } + } + + @Override +- @Override +- public List<ServerPlayer> getPlayers(ChunkPos chunkpos, boolean flag) { ++ public List<ServerPlayer> getPlayers(ChunkPos pos, boolean boundaryOnly) { + Set<ServerPlayer> set = this.playerMap.getAllPlayers(); + Builder<ServerPlayer> builder = ImmutableList.builder(); + Iterator iterator = set.iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- if (flag && this.isChunkOnTrackedBorder(serverplayer, chunkpos.x, chunkpos.z) || !flag && this.isChunkTracked(serverplayer, chunkpos.x, chunkpos.z)) { +- builder.add(serverplayer); ++ if (boundaryOnly && this.isChunkOnTrackedBorder(entityplayer, pos.x, pos.z) || !boundaryOnly && this.isChunkTracked(entityplayer, pos.x, pos.z)) { ++ builder.add(entityplayer); + } + } + +@@ -1252,30 +1297,30 @@ + + protected void addEntity(Entity entity) { + if (!(entity instanceof EnderDragonPart)) { +- EntityType<?> entitytype = entity.getType(); +- int i = entitytype.clientTrackingRange() * 16; ++ EntityType<?> entitytypes = entity.getType(); ++ int i = entitytypes.clientTrackingRange() * 16; + + if (i != 0) { +- int j = entitytype.updateInterval(); ++ int j = entitytypes.updateInterval(); + + if (this.entityMap.containsKey(entity.getId())) { + throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Entity is already tracked!")); + } else { +- ChunkMap.TrackedEntity chunkmap_trackedentity = new ChunkMap.TrackedEntity(entity, i, j, entitytype.trackDeltas()); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); + +- this.entityMap.put(entity.getId(), chunkmap_trackedentity); +- chunkmap_trackedentity.updatePlayers(this.level.players()); ++ this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); ++ playerchunkmap_entitytracker.updatePlayers(this.level.players()); + if (entity instanceof ServerPlayer) { +- ServerPlayer serverplayer = (ServerPlayer) entity; ++ ServerPlayer entityplayer = (ServerPlayer) entity; + +- this.updatePlayerStatus(serverplayer, true); ++ this.updatePlayerStatus(entityplayer, true); + ObjectIterator objectiterator = this.entityMap.values().iterator(); + + while (objectiterator.hasNext()) { +- ChunkMap.TrackedEntity chunkmap_trackedentity1 = (ChunkMap.TrackedEntity) objectiterator.next(); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) objectiterator.next(); + +- if (chunkmap_trackedentity1.entity != serverplayer) { +- chunkmap_trackedentity1.updatePlayer(serverplayer); ++ if (playerchunkmap_entitytracker1.entity != entityplayer) { ++ playerchunkmap_entitytracker1.updatePlayer(entityplayer); + } + } + } +@@ -1287,22 +1332,22 @@ + + protected void removeEntity(Entity entity) { + if (entity instanceof ServerPlayer) { +- ServerPlayer serverplayer = (ServerPlayer) entity; ++ ServerPlayer entityplayer = (ServerPlayer) entity; + +- this.updatePlayerStatus(serverplayer, false); ++ this.updatePlayerStatus(entityplayer, false); + ObjectIterator objectiterator = this.entityMap.values().iterator(); + + while (objectiterator.hasNext()) { +- ChunkMap.TrackedEntity chunkmap_trackedentity = (ChunkMap.TrackedEntity) objectiterator.next(); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); + +- chunkmap_trackedentity.removePlayer(serverplayer); ++ playerchunkmap_entitytracker.removePlayer(entityplayer); + } + } + +- ChunkMap.TrackedEntity chunkmap_trackedentity1 = (ChunkMap.TrackedEntity) this.entityMap.remove(entity.getId()); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) this.entityMap.remove(entity.getId()); + +- if (chunkmap_trackedentity1 != null) { +- chunkmap_trackedentity1.broadcastRemoved(); ++ if (playerchunkmap_entitytracker1 != null) { ++ playerchunkmap_entitytracker1.broadcastRemoved(); + } + + } +@@ -1311,36 +1356,36 @@ + Iterator iterator = this.playerMap.getAllPlayers().iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- this.updateChunkTracking(serverplayer); ++ this.updateChunkTracking(entityplayer); + } + + List<ServerPlayer> list = Lists.newArrayList(); + List<ServerPlayer> list1 = this.level.players(); + ObjectIterator objectiterator = this.entityMap.values().iterator(); + +- ChunkMap.TrackedEntity chunkmap_trackedentity; ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker; + + while (objectiterator.hasNext()) { +- chunkmap_trackedentity = (ChunkMap.TrackedEntity) objectiterator.next(); +- SectionPos sectionpos = chunkmap_trackedentity.lastSectionPos; +- SectionPos sectionpos1 = SectionPos.of((EntityAccess) chunkmap_trackedentity.entity); +- boolean flag = !Objects.equals(sectionpos, sectionpos1); ++ playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); ++ SectionPos sectionposition = playerchunkmap_entitytracker.lastSectionPos; ++ SectionPos sectionposition1 = SectionPos.of((EntityAccess) playerchunkmap_entitytracker.entity); ++ boolean flag = !Objects.equals(sectionposition, sectionposition1); + + if (flag) { +- chunkmap_trackedentity.updatePlayers(list1); +- Entity entity = chunkmap_trackedentity.entity; ++ playerchunkmap_entitytracker.updatePlayers(list1); ++ Entity entity = playerchunkmap_entitytracker.entity; + + if (entity instanceof ServerPlayer) { + list.add((ServerPlayer) entity); + } + +- chunkmap_trackedentity.lastSectionPos = sectionpos1; ++ playerchunkmap_entitytracker.lastSectionPos = sectionposition1; + } + +- if (flag || this.distanceManager.inEntityTickingRange(sectionpos1.chunk().toLong())) { +- chunkmap_trackedentity.serverEntity.sendChanges(); ++ if (flag || this.distanceManager.inEntityTickingRange(sectionposition1.chunk().toLong())) { ++ playerchunkmap_entitytracker.serverEntity.sendChanges(); + } + } + +@@ -1348,61 +1393,61 @@ + objectiterator = this.entityMap.values().iterator(); + + while (objectiterator.hasNext()) { +- chunkmap_trackedentity = (ChunkMap.TrackedEntity) objectiterator.next(); +- chunkmap_trackedentity.updatePlayers(list); ++ playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); ++ playerchunkmap_entitytracker.updatePlayers(list); + } + } + + } + + public void broadcast(Entity entity, Packet<?> packet) { +- ChunkMap.TrackedEntity chunkmap_trackedentity = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); + +- if (chunkmap_trackedentity != null) { +- chunkmap_trackedentity.broadcast(packet); ++ if (playerchunkmap_entitytracker != null) { ++ playerchunkmap_entitytracker.broadcast(packet); + } + + } + + protected void broadcastAndSend(Entity entity, Packet<?> packet) { +- ChunkMap.TrackedEntity chunkmap_trackedentity = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); ++ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); + +- if (chunkmap_trackedentity != null) { +- chunkmap_trackedentity.broadcastAndSend(packet); ++ if (playerchunkmap_entitytracker != null) { ++ playerchunkmap_entitytracker.broadcastAndSend(packet); + } + + } + +- public void resendBiomesForChunks(List<ChunkAccess> list) { ++ public void resendBiomesForChunks(List<ChunkAccess> chunks) { + Map<ServerPlayer, List<LevelChunk>> map = new HashMap(); +- Iterator iterator = list.iterator(); ++ Iterator iterator = chunks.iterator(); + + while (iterator.hasNext()) { +- ChunkAccess chunkaccess = (ChunkAccess) iterator.next(); +- ChunkPos chunkpos = chunkaccess.getPos(); +- LevelChunk levelchunk; ++ ChunkAccess ichunkaccess = (ChunkAccess) iterator.next(); ++ ChunkPos chunkcoordintpair = ichunkaccess.getPos(); ++ LevelChunk chunk; + +- if (chunkaccess instanceof LevelChunk) { +- LevelChunk levelchunk1 = (LevelChunk) chunkaccess; ++ if (ichunkaccess instanceof LevelChunk) { ++ LevelChunk chunk1 = (LevelChunk) ichunkaccess; + +- levelchunk = levelchunk1; ++ chunk = chunk1; + } else { +- levelchunk = this.level.getChunk(chunkpos.x, chunkpos.z); ++ chunk = this.level.getChunk(chunkcoordintpair.x, chunkcoordintpair.z); + } + +- Iterator iterator1 = this.getPlayers(chunkpos, false).iterator(); ++ Iterator iterator1 = this.getPlayers(chunkcoordintpair, false).iterator(); + + while (iterator1.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator1.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator1.next(); + +- ((List) map.computeIfAbsent(serverplayer, (serverplayer1) -> { ++ ((List) map.computeIfAbsent(entityplayer, (entityplayer1) -> { + return new ArrayList(); +- })).add(levelchunk); ++ })).add(chunk); + } + } + +- map.forEach((serverplayer1, list1) -> { +- serverplayer1.connection.send(ClientboundChunksBiomesPacket.forChunks(list1)); ++ map.forEach((entityplayer1, list1) -> { ++ entityplayer1.connection.send(ClientboundChunksBiomesPacket.forChunks(list1)); + }); + } + +@@ -1414,71 +1459,66 @@ + return this.storageName; + } + +- void onFullChunkStatusChange(ChunkPos chunkpos, FullChunkStatus fullchunkstatus) { +- this.chunkStatusListener.onChunkStatusChange(chunkpos, fullchunkstatus); ++ void onFullChunkStatusChange(ChunkPos chunkPos, FullChunkStatus fullChunkStatus) { ++ this.chunkStatusListener.onChunkStatusChange(chunkPos, fullChunkStatus); + } + +- public void waitForLightBeforeSending(ChunkPos chunkpos, int i) { ++ public void waitForLightBeforeSending(ChunkPos chunkcoordintpair, int i) { + int j = i + 1; + +- ChunkPos.rangeClosed(chunkpos, j).forEach((chunkpos1) -> { +- ChunkHolder chunkholder = this.getVisibleChunkIfPresent(chunkpos1.toLong()); ++ ChunkPos.rangeClosed(chunkcoordintpair, j).forEach((chunkcoordintpair1) -> { ++ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(chunkcoordintpair1.toLong()); + +- if (chunkholder != null) { +- chunkholder.addSendDependency(this.lightEngine.waitForPendingTasks(chunkpos1.x, chunkpos1.z)); ++ if (playerchunk != null) { ++ playerchunk.addSendDependency(this.lightEngine.waitForPendingTasks(chunkcoordintpair1.x, chunkcoordintpair1.z)); + } + + }); + } + +- private class DistanceManager extends net.minecraft.server.level.DistanceManager { ++ private class DistanceManager extends DistanceManager { + +- protected DistanceManager(Executor executor, Executor executor1) { +- super(executor, executor1); ++ protected DistanceManager(Executor dispatcher, Executor mainThreadExecutor) { ++ super(dispatcher, mainThreadExecutor); + } + + @Override +- @Override +- protected boolean isChunkToRemove(long i) { +- return ChunkMap.this.toDrop.contains(i); ++ protected boolean isChunkToRemove(long chunkPos) { ++ return ChunkMap.this.toDrop.contains(chunkPos); + } + + @Nullable + @Override +- @Override +- protected ChunkHolder getChunk(long i) { +- return ChunkMap.this.getUpdatingChunkIfPresent(i); ++ protected ChunkHolder getChunk(long chunkPos) { ++ return ChunkMap.this.getUpdatingChunkIfPresent(chunkPos); + } + + @Nullable + @Override +- @Override +- protected ChunkHolder updateChunkScheduling(long i, int j, @Nullable ChunkHolder chunkholder, int k) { +- return ChunkMap.this.updateChunkScheduling(i, j, chunkholder, k); ++ protected ChunkHolder updateChunkScheduling(long chunkPos, int j, @Nullable ChunkHolder newLevel, int holder) { ++ return ChunkMap.this.updateChunkScheduling(chunkPos, j, newLevel, holder); + } + } + +- private class TrackedEntity { ++ public class TrackedEntity { + + final ServerEntity serverEntity; + final Entity entity; + private final int range; + SectionPos lastSectionPos; +- private final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet(); ++ public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet(); + + public TrackedEntity(Entity entity, int i, int j, boolean flag) { +- this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast); ++ this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, seenBy); // CraftBukkit + this.entity = entity; + this.range = i; + this.lastSectionPos = SectionPos.of((EntityAccess) entity); + } + +- @Override + public boolean equals(Object object) { + return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false; + } + +- @Override + public int hashCode() { + return this.entity.getId(); + } +@@ -1513,35 +1553,40 @@ + + } + +- public void removePlayer(ServerPlayer serverplayer) { +- if (this.seenBy.remove(serverplayer.connection)) { +- this.serverEntity.removePairing(serverplayer); ++ public void removePlayer(ServerPlayer player) { ++ if (this.seenBy.remove(player.connection)) { ++ this.serverEntity.removePairing(player); + } + + } + +- public void updatePlayer(ServerPlayer serverplayer) { +- if (serverplayer != this.entity) { +- Vec3 vec3 = serverplayer.position().subtract(this.entity.position()); +- int i = ChunkMap.this.getPlayerViewDistance(serverplayer); ++ public void updatePlayer(ServerPlayer player) { ++ if (player != this.entity) { ++ Vec3 vec3d = player.position().subtract(this.entity.position()); ++ int i = ChunkMap.this.getPlayerViewDistance(player); + double d0 = (double) Math.min(this.getEffectiveRange(), i * 16); +- double d1 = vec3.x * vec3.x + vec3.z * vec3.z; ++ double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; + double d2 = d0 * d0; +- boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(serverplayer) && ChunkMap.this.isChunkTracked(serverplayer, this.entity.chunkPosition().x, this.entity.chunkPosition().z); ++ boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); + ++ // CraftBukkit start - respect vanish API ++ if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { ++ flag = false; ++ } ++ // CraftBukkit end + if (flag) { +- if (this.seenBy.add(serverplayer.connection)) { +- this.serverEntity.addPairing(serverplayer); ++ if (this.seenBy.add(player.connection)) { ++ this.serverEntity.addPairing(player); + } +- } else if (this.seenBy.remove(serverplayer.connection)) { +- this.serverEntity.removePairing(serverplayer); ++ } else if (this.seenBy.remove(player.connection)) { ++ this.serverEntity.removePairing(player); + } + + } + } + +- private int scaledRange(int i) { +- return ChunkMap.this.level.getServer().getScaledTrackingDistance(i); ++ private int scaledRange(int trackingDistance) { ++ return ChunkMap.this.level.getServer().getScaledTrackingDistance(trackingDistance); + } + + private int getEffectiveRange() { +@@ -1560,13 +1605,13 @@ + return this.scaledRange(i); + } + +- public void updatePlayers(List<ServerPlayer> list) { +- Iterator iterator = list.iterator(); ++ public void updatePlayers(List<ServerPlayer> playersList) { ++ Iterator iterator = playersList.iterator(); + + while (iterator.hasNext()) { +- ServerPlayer serverplayer = (ServerPlayer) iterator.next(); ++ ServerPlayer entityplayer = (ServerPlayer) iterator.next(); + +- this.updatePlayer(serverplayer); ++ this.updatePlayer(entityplayer); + } + + } |