--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -72,6 +_,12 @@
         }
 
         if (!this.chunksToUpdateFutures.isEmpty()) {
+            // CraftBukkit start - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus
+            for (final ChunkHolder chunkHolder : this.chunksToUpdateFutures) {
+                chunkHolder.callEventIfUnloading(chunkMap);
+            }
+            // CraftBukkit end - SPIGOT-7780: Call chunk unload events before updateHighestAllowedStatus
+
             for (ChunkHolder chunkHolder : this.chunksToUpdateFutures) {
                 chunkHolder.updateHighestAllowedStatus(chunkMap);
             }
@@ -121,8 +_,10 @@
         ChunkPos chunkPos = sectionPos.chunk();
         long packedChunkPos = chunkPos.toLong();
         ObjectSet<ServerPlayer> set = this.playersPerChunk.get(packedChunkPos);
-        set.remove(player);
-        if (set.isEmpty()) {
+        // Paper start - some state corruption happens here, don't crash, clean up gracefully
+        if (set != null) set.remove(player);
+        if (set == null || set.isEmpty()) {
+        // Paper end - some state corruption happens here, don't crash, clean up gracefully
             this.playersPerChunk.remove(packedChunkPos);
             this.naturalSpawnChunkCounter.update(packedChunkPos, Integer.MAX_VALUE, false);
             this.playerTicketManager.update(packedChunkPos, Integer.MAX_VALUE, false);
