aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0736-Prevent-unload-calls-removing-tickets-for-sync-loads.patch
blob: e2c44162345efc90da8f1cd1caf37a1a8381117c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index d2865ce0523b74aaa935db72c6f3478894e13408..ea4e46c113d3f0a5db6c891021e2e4c5eb275cd4 100644
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -545,7 +545,7 @@ public abstract class DistanceManager {
     }
 
     public void removeTicketsOnClosing() {
-        ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.LIGHT, TicketType.FUTURE_AWAIT, TicketType.ASYNC_LOAD); // Paper - add additional tickets to preserve
+        ImmutableSet<TicketType<?>> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.LIGHT, TicketType.FUTURE_AWAIT, TicketType.ASYNC_LOAD, TicketType.REQUIRED_LOAD); // Paper - add additional tickets to preserve
         ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator();
 
         while (objectiterator.hasNext()) {
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 718c89f421637d623a92e5167397870562593a04..adab778c11ef11cb57418675a98129afb01ec06e 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -721,6 +721,8 @@ public class ServerChunkCache extends ChunkSource {
         return completablefuture;
     }
 
+    private long syncLoadCounter; // Paper - prevent plugin unloads from removing our ticket
+
     private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
         // Paper start - add isUrgent - old sig left in place for dirty nms plugins
         return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false);
@@ -739,9 +741,12 @@ public class ServerChunkCache extends ChunkSource {
             ChunkHolder.FullChunkStatus currentChunkState = ChunkHolder.getFullChunkStatus(playerchunk.getTicketLevel());
             currentlyUnloading = (oldChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !currentChunkState.isOrAfter(ChunkHolder.FullChunkStatus.BORDER));
         }
+        final Long identifier; // Paper - prevent plugin unloads from removing our ticket
         if (create && !currentlyUnloading) {
             // CraftBukkit end
             this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
+            identifier = Long.valueOf(this.syncLoadCounter++); // Paper - prevent plugin unloads from removing our ticket
+            this.distanceManager.addTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Paper - prevent plugin unloads from removing our ticket
             if (isUrgent) this.distanceManager.markUrgent(chunkcoordintpair); // Paper - Chunk priority
             if (this.chunkAbsent(playerchunk, l)) {
                 ProfilerFiller gameprofilerfiller = this.level.getProfiler();
@@ -752,13 +757,21 @@ public class ServerChunkCache extends ChunkSource {
                 playerchunk = this.getVisibleChunkIfPresent(k);
                 gameprofilerfiller.pop();
                 if (this.chunkAbsent(playerchunk, l)) {
+                    this.distanceManager.removeTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier); // Paper
                     throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added"));
                 }
             }
-        }
 
+        } else { identifier = null; } // Paper - prevent plugin unloads from removing our ticket
         // Paper start - Chunk priority
         CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(leastStatus, this.chunkMap);
+        // Paper start - prevent plugin unloads from removing our ticket
+        if (create && !currentlyUnloading) {
+            future.thenAcceptAsync((either) -> {
+                ServerChunkCache.this.distanceManager.removeTicket(TicketType.REQUIRED_LOAD, chunkcoordintpair, l, identifier);
+            }, ServerChunkCache.this.mainThreadProcessor);
+        }
+        // Paper end - prevent plugin unloads from removing our ticket
         if (isUrgent) {
             future.thenAccept(either -> this.distanceManager.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 3c1698ba0d3bc412ab957777d9b5211dbc555208..41ddcf6775f99c56cf4b13b284420061e5dd6bdc 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<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
     public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
     public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
+    public static final TicketType<Long> REQUIRED_LOAD = create("required_load", Long::compareTo); // Paper - make sure getChunkAt does not fail
 
     public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
         return new TicketType<>(name, argumentComparator, 0L);