From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Thu, 18 Jun 2020 18:23:20 -0700
Subject: [PATCH] Prevent unload() calls removing tickets for sync loads


diff --git a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
index 3560ac0c554b8e60c1bc961766bcf942ba6dd963..aa673cf8a11c17faaa1520eaa9329200453a53ff 100644
--- a/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/level/ChunkProviderServer.java
@@ -734,6 +734,8 @@ public class ChunkProviderServer extends IChunkProvider {
         Arrays.fill(this.cacheChunk, (Object) null);
     }
 
+    private long syncLoadCounter; // Tuinity - prevent plugin unloads from removing our ticket
+
     private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getChunkFutureMainThread(int i, int j, ChunkStatus chunkstatus, boolean flag) {
         // Paper start - add isUrgent - old sig left in place for dirty nms plugins
         return getChunkFutureMainThread(i, j, chunkstatus, flag, false);
@@ -752,9 +754,12 @@ public class ChunkProviderServer extends IChunkProvider {
             PlayerChunk.State currentChunkState = PlayerChunk.getChunkState(playerchunk.getTicketLevel());
             currentlyUnloading = (oldChunkState.isAtLeast(PlayerChunk.State.BORDER) && !currentChunkState.isAtLeast(PlayerChunk.State.BORDER));
         }
+        final Long identifier; // Tuinity - prevent plugin unloads from removing our ticket
         if (flag && !currentlyUnloading) {
             // CraftBukkit end
             this.chunkMapDistance.a(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
+            identifier = Long.valueOf(this.syncLoadCounter++); // Tuinity - prevent plugin unloads from removing our ticket
+            this.chunkMapDistance.addTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Tuinity - prevent plugin unloads from removing our ticket
             if (isUrgent) this.chunkMapDistance.markUrgent(chunkcoordintpair); // Paper
             if (this.a(playerchunk, l)) {
                 GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler();
@@ -765,12 +770,20 @@ public class ChunkProviderServer extends IChunkProvider {
                 playerchunk = this.getChunk(k);
                 gameprofilerfiller.exit();
                 if (this.a(playerchunk, l)) {
+                    this.chunkMapDistance.removeTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Tuinity
                     throw (IllegalStateException) SystemUtils.c((Throwable) (new IllegalStateException("No chunk holder after ticket has been added")));
                 }
             }
-        }
+        } else { identifier = null; } // Tuinity - prevent plugin unloads from removing our ticket
         // Paper start
         CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> future = this.a(playerchunk, l) ? PlayerChunk.UNLOADED_CHUNK_ACCESS_FUTURE : playerchunk.a(chunkstatus, this.playerChunkMap);
+        // Tuinity start - prevent plugin unloads from removing our ticket
+        if (flag && !currentlyUnloading) {
+            future.thenAcceptAsync((either) -> {
+                ChunkProviderServer.this.chunkMapDistance.removeTicketAtLevel(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier);
+            }, ChunkProviderServer.this.serverThreadQueue);
+        }
+        // Tuinity end - prevent plugin unloads from removing our ticket
         if (isUrgent) {
             future.thenAccept(either -> this.chunkMapDistance.clearUrgent(chunkcoordintpair));
         }
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
index 47da7efffde2e6d63c1a064b950abf8135705622..1122df50a7f9cbc489e8da7a91e9af73476eb148 100644
--- a/src/main/java/net/minecraft/server/level/TicketType.java
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
@@ -31,6 +31,7 @@ public class TicketType<T> {
     public static final TicketType<ChunkCoordIntPair> PRIORITY = a("priority", Comparator.comparingLong(ChunkCoordIntPair::pair), 300); // Paper
     public static final TicketType<ChunkCoordIntPair> URGENT = a("urgent", Comparator.comparingLong(ChunkCoordIntPair::pair), 300); // Paper
     public static final TicketType<Long> DELAYED_UNLOAD = a("delayed_unload", Long::compareTo); // Tuinity - delay chunk unloads
+    public static final TicketType<Long> REQUIRED_LOAD = a("required_load", Long::compareTo); // Tuinity - make sure getChunkAt does not fail
 
     // Tuinity start - delay chunk unloads
     boolean delayUnloadViable = true;
