diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityAccess.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch similarity index 50% rename from paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityAccess.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch index 517de585e8..6c5e3be1cc 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityAccess.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityAccess.java.patch @@ -1,21 +1,11 @@ --- a/net/minecraft/world/level/entity/EntityAccess.java +++ b/net/minecraft/world/level/entity/EntityAccess.java -@@ -5,6 +5,9 @@ - import net.minecraft.core.BlockPos; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.phys.AABB; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end +@@ -23,6 +_,12 @@ - public interface EntityAccess { - -@@ -24,6 +27,12 @@ - - void setRemoved(Entity.RemovalReason reason); + void setRemoved(Entity.RemovalReason removalReason); + // CraftBukkit start - add Bukkit remove cause -+ default void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { ++ default void setRemoved(Entity.RemovalReason entity_removalreason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { + this.setRemoved(entity_removalreason); + } + // CraftBukkit end diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityLookup.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityLookup.java.patch similarity index 71% rename from paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityLookup.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/entity/EntityLookup.java.patch index b3b9c9ccb4..900da01b8e 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/entity/EntityLookup.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/EntityLookup.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/entity/EntityLookup.java +++ b/net/minecraft/world/level/entity/EntityLookup.java -@@ -33,6 +33,14 @@ - UUID uUID = entity.getUUID(); - if (this.byUuid.containsKey(uUID)) { - LOGGER.warn("Duplicate entity UUID {}: {}", uUID, entity); +@@ -33,6 +_,14 @@ + UUID uuid = entity.getUUID(); + if (this.byUuid.containsKey(uuid)) { + LOGGER.warn("Duplicate entity UUID {}: {}", uuid, entity); + // Paper start - extra debug info + if (entity instanceof net.minecraft.world.entity.Entity) { + final T old = this.byUuid.get(entity.getUUID()); @@ -11,7 +11,7 @@ + LOGGER.error("Overwrote an existing entity {} with {}", oldCast, entity); + } + } -+ // Paper end - extra debug info ++ // Paper end } else { - this.byUuid.put(uUID, entity); + this.byUuid.put(uuid, entity); this.byId.put(entity.getId(), entity); diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch new file mode 100644 index 0000000000..2fce5aff6c --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch @@ -0,0 +1,208 @@ +--- a/net/minecraft/world/level/entity/PersistentEntitySectionManager.java ++++ b/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +@@ -52,6 +_,16 @@ + this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage); + } + ++ // CraftBukkit start - add method to get all entities in chunk ++ public List getEntities(ChunkPos chunkCoordIntPair) { ++ return this.sectionStorage.getExistingSectionsInChunk(chunkCoordIntPair.toLong()).flatMap(EntitySection::getEntities).map(entity -> (Entity) entity).collect(Collectors.toList()); ++ } ++ ++ public boolean isPending(long pair) { ++ return this.chunkLoadStatuses.get(pair) == ChunkLoadStatus.PENDING; ++ } ++ // CraftBukkit end ++ + void removeSectionIfEmpty(long sectionKey, EntitySection section) { + if (section.isEmpty()) { + this.sectionStorage.remove(sectionKey); +@@ -59,6 +_,7 @@ + } + + private boolean addEntityUuid(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper + if (!this.knownUuids.add(entity.getUUID())) { + LOGGER.warn("UUID of added entity already exists: {}", entity); + return false; +@@ -72,6 +_,17 @@ + } + + private boolean addEntity(T entity, boolean worldGenSpawned) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper ++ // Paper start - chunk system hooks ++ // I don't want to know why this is a generic type. ++ Entity entityCasted = (Entity)entity; ++ boolean wasRemoved = entityCasted.isRemoved(); ++ boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true); ++ if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { ++ // removed by callback ++ return false; ++ } ++ // Paper end - chunk system hooks + if (!this.addEntityUuid(entity)) { + return false; + } else { +@@ -109,19 +_,23 @@ + } + + void startTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper + this.callbacks.onTickingStart(entity); + } + + void stopTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper + this.callbacks.onTickingEnd(entity); + } + + void startTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper + this.visibleEntityStorage.add(entity); + this.callbacks.onTrackingStart(entity); + } + + void stopTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper + this.callbacks.onTrackingEnd(entity); + this.visibleEntityStorage.remove(entity); + } +@@ -132,6 +_,7 @@ + } + + public void updateChunkStatus(ChunkPos pos, Visibility visibility) { ++ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper + long packedChunkPos = pos.toLong(); + if (visibility == Visibility.HIDDEN) { + this.chunkVisibility.remove(packedChunkPos); +@@ -165,6 +_,7 @@ + } + + public void ensureChunkQueuedForLoad(long chunkPosValue) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper + PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue); + if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { + this.requestChunkLoad(chunkPosValue); +@@ -172,6 +_,11 @@ + } + + private boolean storeChunkSections(long chunkPosValue, Consumer entityAction) { ++ // CraftBukkit start ++ return storeChunkSections(chunkPosValue, entityAction, false); ++ } ++ private boolean storeChunkSections(long chunkPosValue, Consumer entityAction, boolean callEvent) { ++ // CraftBukkit end + PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPosValue); + if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) { + return false; +@@ -182,6 +_,7 @@ + .collect(Collectors.toList()); + if (list.isEmpty()) { + if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) { ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(chunkPosValue), ImmutableList.of()); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), ImmutableList.of())); + } + +@@ -190,6 +_,7 @@ + this.requestChunkLoad(chunkPosValue); + return false; + } else { ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, new ChunkPos(i), list.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPosValue), list)); + list.forEach(entityAction); + return true; +@@ -198,6 +_,7 @@ + } + + private void requestChunkLoad(long chunkPosValue) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper + this.chunkLoadStatuses.put(chunkPosValue, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); + ChunkPos chunkPos = new ChunkPos(chunkPosValue); + this.permanentStorage.loadEntities(chunkPos).thenAccept(this.loadingInbox::add).exceptionally(throwable -> { +@@ -207,7 +_,8 @@ + } + + private boolean processChunkUnload(long chunkPosValue) { +- boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity)); ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper ++ boolean flag = this.storeChunkSections(chunkPosValue, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity), true); // CraftBukkit - add boolean for event call + if (!flag) { + return false; + } else { +@@ -217,7 +_,7 @@ + } + + private void unloadEntity(EntityAccess entity) { +- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); ++ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); // CraftBukkit - add Bukkit remove cause + entity.setLevelCallback(EntityInLevelCallback.NULL); + } + +@@ -227,14 +_,20 @@ + } + + private void processPendingLoads() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper + ChunkEntities chunkEntities; + while ((chunkEntities = this.loadingInbox.poll()) != null) { + chunkEntities.getEntities().forEach(entity -> this.addEntity((T)entity, true)); + this.chunkLoadStatuses.put(chunkEntities.getPos().toLong(), PersistentEntitySectionManager.ChunkLoadStatus.LOADED); ++ // CraftBukkit start - call entity load event ++ List entities = this.getEntities(chunkEntities.getPos()); ++ org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesLoadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, chunkentities.getPos(), entities); ++ // CraftBukkit end + } + } + + public void tick() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper + this.processPendingLoads(); + this.processUnloads(); + } +@@ -252,6 +_,7 @@ + } + + public void autoSave() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper + this.getAllChunksToSave().forEach(packedChunkPos -> { + boolean flag = this.chunkVisibility.get(packedChunkPos) == Visibility.HIDDEN; + if (flag) { +@@ -263,6 +_,7 @@ + } + + public void saveAll() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper + LongSet allChunksToSave = this.getAllChunksToSave(); + + while (!allChunksToSave.isEmpty()) { +@@ -279,7 +_,13 @@ + + @Override + public void close() throws IOException { +- this.saveAll(); ++ // CraftBukkit start ++ this.close(true); ++ } ++ ++ public void close(boolean save) throws IOException { ++ if (save) this.saveAll(); ++ // CraftBukkit end + this.permanentStorage.close(); + } + +@@ -380,6 +_,7 @@ + BlockPos blockPos = this.entity.blockPosition(); + long packedSectionPos = SectionPos.asLong(blockPos); + if (packedSectionPos != this.currentSectionKey) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper + Visibility status = this.currentSection.getStatus(); + if (!this.currentSection.remove(this.entity)) { + PersistentEntitySectionManager.LOGGER +@@ -427,6 +_,7 @@ + + @Override + public void onRemove(Entity.RemovalReason reason) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper + if (!this.currentSection.remove(this.entity)) { + PersistentEntitySectionManager.LOGGER + .warn("Entity {} wasn't found in section {} (destroying due to {})", this.entity, SectionPos.of(this.currentSectionKey), reason); diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch deleted file mode 100644 index 68a70b169a..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch +++ /dev/null @@ -1,276 +0,0 @@ ---- a/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -+++ b/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -29,8 +29,13 @@ - import net.minecraft.util.CsvOutput; - import net.minecraft.util.VisibleForDebug; - import net.minecraft.world.entity.Entity; --import net.minecraft.world.level.ChunkPos; - import org.slf4j.Logger; -+import net.minecraft.world.level.ChunkPos; -+// CraftBukkit start -+import net.minecraft.world.level.chunk.storage.EntityStorage; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class PersistentEntitySectionManager implements AutoCloseable { - -@@ -55,6 +60,16 @@ - this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage); - } - -+ // CraftBukkit start - add method to get all entities in chunk -+ public List getEntities(ChunkPos chunkCoordIntPair) { -+ return this.sectionStorage.getExistingSectionsInChunk(chunkCoordIntPair.toLong()).flatMap(EntitySection::getEntities).map(entity -> (Entity) entity).collect(Collectors.toList()); -+ } -+ -+ public boolean isPending(long pair) { -+ return this.chunkLoadStatuses.get(pair) == ChunkLoadStatus.PENDING; -+ } -+ // CraftBukkit end -+ - void removeSectionIfEmpty(long sectionPos, EntitySection section) { - if (section.isEmpty()) { - this.sectionStorage.remove(sectionPos); -@@ -63,6 +78,7 @@ - } - - private boolean addEntityUuid(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper - if (!this.knownUuids.add(entity.getUUID())) { - PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity); - return false; -@@ -76,6 +92,17 @@ - } - - private boolean addEntity(T entity, boolean existing) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper -+ // Paper start - chunk system hooks -+ // I don't want to know why this is a generic type. -+ Entity entityCasted = (Entity)entity; -+ boolean wasRemoved = entityCasted.isRemoved(); -+ boolean screened = ca.spottedleaf.moonrise.common.util.ChunkSystem.screenEntity((net.minecraft.server.level.ServerLevel)entityCasted.level(), entityCasted, existing, true); -+ if ((!wasRemoved && entityCasted.isRemoved()) || !screened) { -+ // removed by callback -+ return false; -+ } -+ // Paper end - chunk system hooks - if (!this.addEntityUuid(entity)) { - return false; - } else { -@@ -119,19 +146,23 @@ - } - - void startTicking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper - this.callbacks.onTickingStart(entity); - } - - void stopTicking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper - this.callbacks.onTickingEnd(entity); - } - - void startTracking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper - this.visibleEntityStorage.add(entity); - this.callbacks.onTrackingStart(entity); - } - - void stopTracking(T entity) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper - this.callbacks.onTrackingEnd(entity); - this.visibleEntityStorage.remove(entity); - } -@@ -143,6 +174,7 @@ - } - - public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { -+ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper - long i = chunkPos.toLong(); - - if (trackingStatus == Visibility.HIDDEN) { -@@ -187,6 +219,7 @@ - } - - public void ensureChunkQueuedForLoad(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper - PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); - - if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { -@@ -196,33 +229,42 @@ - } - - private boolean storeChunkSections(long chunkPos, Consumer action) { -- PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); -+ // CraftBukkit start - add boolean for event call -+ return this.storeChunkSections(chunkPos, action, false); -+ } - -+ private boolean storeChunkSections(long i, Consumer consumer, boolean callEvent) { -+ // CraftBukkit end -+ PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(i); -+ - if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) { - return false; - } else { -- List list = (List) this.sectionStorage.getExistingSectionsInChunk(chunkPos).flatMap((entitysection) -> { -+ List list = (List) this.sectionStorage.getExistingSectionsInChunk(i).flatMap((entitysection) -> { - return entitysection.getEntities().filter(EntityAccess::shouldBeSaved); - }).collect(Collectors.toList()); - - if (list.isEmpty()) { - if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) { -- this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPos), ImmutableList.of())); -+ if (callEvent) CraftEventFactory.callEntitiesUnloadEvent(((EntityStorage) this.permanentStorage).level, new ChunkPos(i), ImmutableList.of()); // CraftBukkit -+ this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(i), ImmutableList.of())); - } - - return true; - } else if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { -- this.requestChunkLoad(chunkPos); -+ this.requestChunkLoad(i); - return false; - } else { -- this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(chunkPos), list)); -- list.forEach(action); -+ if (callEvent) CraftEventFactory.callEntitiesUnloadEvent(((EntityStorage) this.permanentStorage).level, new ChunkPos(i), list.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit -+ this.permanentStorage.storeEntities(new ChunkEntities<>(new ChunkPos(i), list)); -+ list.forEach(consumer); - return true; - } - } - } - - private void requestChunkLoad(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper - this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); - ChunkPos chunkcoordintpair = new ChunkPos(chunkPos); - CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair); -@@ -236,9 +278,10 @@ - } - - private boolean processChunkUnload(long chunkPos) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper - boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> { - entityaccess.getPassengersAndSelf().forEach(this::unloadEntity); -- }); -+ }, true); // CraftBukkit - add boolean for event call - - if (!flag) { - return false; -@@ -249,29 +292,35 @@ - } - - private void unloadEntity(EntityAccess entity) { -- entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK); -+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, EntityRemoveEvent.Cause.UNLOAD); // CraftBukkit - add Bukkit remove cause - entity.setLevelCallback(EntityInLevelCallback.NULL); - } - - private void processUnloads() { -- this.chunksToUnload.removeIf((i) -> { -+ this.chunksToUnload.removeIf((java.util.function.LongPredicate) (i) -> { // CraftBukkit - decompile error - return this.chunkVisibility.get(i) != Visibility.HIDDEN ? true : this.processChunkUnload(i); - }); - } - - private void processPendingLoads() { -- ChunkEntities chunkentities; -+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper -+ ChunkEntities chunkentities; // CraftBukkit - decompile error - - while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { - chunkentities.getEntities().forEach((entityaccess) -> { - this.addEntity(entityaccess, true); - }); - this.chunkLoadStatuses.put(chunkentities.getPos().toLong(), PersistentEntitySectionManager.ChunkLoadStatus.LOADED); -+ // CraftBukkit start - call entity load event -+ List entities = this.getEntities(chunkentities.getPos()); -+ CraftEventFactory.callEntitiesLoadEvent(((EntityStorage) this.permanentStorage).level, chunkentities.getPos(), entities); -+ // CraftBukkit end - } - - } - - public void tick() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper - this.processPendingLoads(); - this.processUnloads(); - } -@@ -292,7 +341,8 @@ - } - - public void autoSave() { -- this.getAllChunksToSave().forEach((i) -> { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper -+ this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error - boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; - - if (flag) { -@@ -306,12 +356,13 @@ - } - - public void saveAll() { -+ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper - LongSet longset = this.getAllChunksToSave(); - - while (!longset.isEmpty()) { - this.permanentStorage.flush(false); - this.processPendingLoads(); -- longset.removeIf((i) -> { -+ longset.removeIf((java.util.function.LongPredicate) (i) -> { // CraftBukkit - decompile error - boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; - - return flag ? this.processChunkUnload(i) : this.storeChunkSections(i, (entityaccess) -> { -@@ -323,7 +374,15 @@ - } - - public void close() throws IOException { -- this.saveAll(); -+ // CraftBukkit start - add save boolean -+ this.close(true); -+ } -+ -+ public void close(boolean save) throws IOException { -+ if (save) { -+ this.saveAll(); -+ } -+ // CraftBukkit end - this.permanentStorage.close(); - } - -@@ -350,7 +409,7 @@ - public void dumpSections(Writer writer) throws IOException { - CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("visibility").addColumn("load_status").addColumn("entity_count").build(writer); - -- this.sectionStorage.getAllChunksWithExistingSections().forEach((i) -> { -+ this.sectionStorage.getAllChunksWithExistingSections().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error - PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(i); - - this.sectionStorage.getExistingSectionPositionsInChunk(i).forEach((j) -> { -@@ -394,7 +453,7 @@ - private EntitySection currentSection; - - Callback(final EntityAccess entityaccess, final long i, final EntitySection entitysection) { -- this.entity = entityaccess; -+ this.entity = (T) entityaccess; // CraftBukkit - decompile error - this.currentSectionKey = i; - this.currentSection = entitysection; - } -@@ -405,6 +464,7 @@ - long i = SectionPos.asLong(blockposition); - - if (i != this.currentSectionKey) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper - Visibility visibility = this.currentSection.getStatus(); - - if (!this.currentSection.remove(this.entity)) { -@@ -459,6 +519,7 @@ - - @Override - public void onRemove(Entity.RemovalReason reason) { -+ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper - if (!this.currentSection.remove(this.entity)) { - PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); - }