aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower/net/minecraft/server/level/ChunkMap.java.patch
diff options
context:
space:
mode:
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.patch1896
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);
+ }
+
+ }