Guest User

Untitled

a guest
Jul 21st, 2018
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.38 KB | None | 0 0
  1. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
  2. index 1f50004cb..1fdc2ac6e 100644
  3. --- a/src/main/java/net/minecraft/server/Chunk.java
  4. +++ b/src/main/java/net/minecraft/server/Chunk.java
  5. @@ -1386,7 +1386,7 @@ public class Chunk implements IChunkAccess {
  6. throw new RuntimeException("Error while adding chunk to cache. Too many neighbors");
  7. } else {
  8. if (this.K()) {
  9. - ((IAsyncTaskHandler) this.world).postToMainThread(this::E);
  10. + MCUtil.ensureMain(this::E); // Paper - use processQueue instead of the other queue
  11. }
  12.  
  13. }
  14. diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
  15. index 7f83ed51d..f70b92555 100644
  16. --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
  17. +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
  18. @@ -47,7 +47,7 @@ public class ChunkProviderServer implements IChunkProvider {
  19. this.world = worldserver;
  20. this.chunkLoader = ichunkloader;
  21. this.chunkGenerator = chunkgenerator;
  22. - this.f = new ChunkTaskScheduler(0, worldserver, chunkgenerator, ichunkloader, iasynctaskhandler); // CraftBukkit - very buggy, broken in lots of __subtle__ ways. Same goes for async chunk loading. Also Bukkit API / plugins can't handle async events at all anyway.
  23. + this.f = new ChunkTaskScheduler(2, worldserver, chunkgenerator, ichunkloader, iasynctaskhandler); // CraftBukkit - very buggy, broken in lots of __subtle__ ways. Same goes for async chunk loading. Also Bukkit API / plugins can't handle async events at all anyway. // Paper
  24. this.g = new SchedulerBatch(this.f);
  25. }
  26.  
  27. @@ -108,12 +108,38 @@ public class ChunkProviderServer implements IChunkProvider {
  28.  
  29. @Nullable
  30. public Chunk getOrLoadChunkAt(int i, int j) {
  31. - Long2ObjectMap long2objectmap = this.chunks;
  32. -
  33. - synchronized (this.chunks) {
  34. + // Paper start
  35. + return getOrLoadChunkAt(i, j, null);
  36. + }
  37. + public Chunk getOrLoadChunkAtOrig(int i, int j, Runnable runnable) {
  38. + synchronized (this.chunkLoader) {
  39. + Chunk chunk = getChunkIfLoaded(i, j);
  40. + return chunk != null ? chunk : loadChunkAt(i, j);
  41. + }
  42. + }
  43. + public Chunk getOrLoadChunkAt(int i, int j, Runnable runnable) {
  44. + synchronized (this.chunkLoader) {
  45. Chunk chunk = world.paperConfig.allowPermaChunkLoaders ? getLoadedChunkAt(i, j) : getChunkIfLoaded(i, j); // Paper - Configurable perma chunk loaders
  46. -
  47. - return chunk != null ? chunk : this.loadChunkAt(i, j);
  48. + if (!this.chunkLoader.chunkExists(i, j)) {
  49. + return null;
  50. + }
  51. + long key = ChunkCoordIntPair.asLong(i, j);
  52. + CompletableFuture<Chunk> pending = pendingGenerates.get(key);
  53. + if (pending != null) {
  54. + return null; // get getChunkAt handle it
  55. + }
  56. + if (chunk == null && runnable != null) {
  57. + ChunkIOExecutor.queueChunkLoad(world, (ChunkRegionLoader) this.chunkLoader, this, i, j, runnable);
  58. + return null;
  59. + }
  60. + if (chunk == null) {
  61. + chunk = ChunkIOExecutor.syncChunkLoad(world, (ChunkRegionLoader) chunkLoader, this, i, j);
  62. + }
  63. + if (chunk != null && runnable != null) {
  64. + runnable.run();
  65. + }
  66. + return chunk;
  67. + // Paper end
  68. }
  69. }
  70.  
  71. @@ -123,21 +149,67 @@ public class ChunkProviderServer implements IChunkProvider {
  72. }
  73. // CraftBukkit end
  74.  
  75. + // Paper sart
  76. + private final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<CompletableFuture<Chunk>> pendingGenerates = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
  77. + public CompletableFuture<Chunk> generateChunk(int i, int j) { // Incase something else calls this
  78. + return generateChunk(i, j, null);
  79. + }
  80. +
  81. + private CompletableFuture<Chunk> postChunkgenMain(ProtoChunk proto) {
  82. + CompletableFuture<Chunk> pending = new CompletableFuture<>();
  83. + MCUtil.ensureMain(() -> {
  84. + try {
  85. + pending.complete(this.finishChunkgen(proto));
  86. + } catch (Exception e) {
  87. + pending.completeExceptionally(e);
  88. + }
  89. + });
  90. + return pending;
  91. + }
  92. + public synchronized CompletableFuture<Chunk> generateChunk(int i, int j, Consumer<Chunk> consumer) {
  93. + long key = ChunkCoordIntPair.asLong(i, j);
  94. + CompletableFuture<Chunk> pending = pendingGenerates.get(key);
  95. + if (pending == null) {
  96. + pending = this.generateChunk0(i, j);
  97. + pendingGenerates.put(key, pending);
  98. + pending.thenAccept(unused -> {
  99. + synchronized (pendingGenerates) {
  100. + pendingGenerates.remove(key);
  101. + }
  102. + });
  103. + }
  104. +
  105. + if (consumer != null) {
  106. + pending.thenAccept(chunk -> MCUtil.ensureMain(() -> consumer.accept(chunk)));
  107. + }
  108. + return pending;
  109. + }
  110. +
  111. public Chunk getChunkAt(int i, int j) {
  112. - Chunk chunk = this.getOrLoadChunkAt(i, j);
  113. + return getChunkAt(i, j, null, true);
  114. + }
  115. + public Chunk getChunkAt(int i, int j, Runnable runnable) {
  116. + return getChunkAt(i, j, runnable, true);
  117. + }
  118. + public Chunk getChunkAt(int i, int j, Runnable runnable, boolean generate) {
  119. + // Paper end
  120. + Chunk chunk = this.getOrLoadChunkAt(i, j, runnable);
  121.  
  122. if (chunk != null) {
  123. return chunk;
  124. - } else {
  125. + } else if (generate) { // Paper
  126. try {
  127. world.timings.syncChunkLoadTimer.startTiming(); // Spigot
  128. - chunk = (Chunk) this.generateChunk(i, j).get();
  129. - return chunk;
  130. - } catch (ExecutionException | InterruptedException interruptedexception) {
  131. + // Paper start
  132. + CompletableFuture<Chunk> pending = generateChunk(i, j, runnable != null ? unused -> runnable.run() : null);
  133. + return runnable != null ? null : MCUtil.processQueueWhileWaiting(pending);
  134. + } catch (Exception interruptedexception) {
  135. + // Paper end
  136. throw this.a(i, j, (Throwable) interruptedexception);
  137. }
  138. finally { world.timings.syncChunkLoadTimer.stopTiming(); } // Spigot
  139. }
  140. + return null; // Paper
  141. }
  142.  
  143. public IChunkAccess d(int i, int j) {
  144. @@ -161,19 +233,23 @@ public class ChunkProviderServer implements IChunkProvider {
  145. if (chunk != null) {
  146. consumer.accept(chunk);
  147. } else {
  148. - this.g.a(chunkcoordintpair).thenApply(this::a).thenAccept(consumer);
  149. + this.g.a(chunkcoordintpair).thenApply(proto -> postChunkgenMain(proto).thenAccept(consumer)); // Paper
  150. }
  151. }
  152.  
  153. return this.g.c();
  154. }
  155.  
  156. - public CompletableFuture<Chunk> generateChunk(int i, int j) {
  157. + private CompletableFuture<Chunk> generateChunk0(int i, int j) { // Paper - make private, change name
  158. this.g.b();
  159. this.g.a(new ChunkCoordIntPair(i, j));
  160. CompletableFuture<ProtoChunk> completablefuture = this.g.c(); // CraftBukkit - decompile error
  161.  
  162. - return completablefuture.thenApply(this::a);
  163. + // Paper start
  164. + CompletableFuture<Chunk> pending = new CompletableFuture<>();
  165. + completablefuture.thenApply(proto -> postChunkgenMain(proto).thenAccept(pending::complete));
  166. + return pending;
  167. + // Paper end
  168. }
  169.  
  170. private ReportedException a(int i, int j, Throwable throwable) {
  171. @@ -186,7 +262,7 @@ public class ChunkProviderServer implements IChunkProvider {
  172. return new ReportedException(crashreport);
  173. }
  174.  
  175. - private Chunk a(IChunkAccess ichunkaccess) {
  176. + private Chunk finishChunkgen(IChunkAccess ichunkaccess) { // Paper - rename method - Anything that accesses this should ensure it goes through process to ensure it is on main thread
  177. ChunkCoordIntPair chunkcoordintpair = ichunkaccess.getPos();
  178. int i = chunkcoordintpair.x;
  179. int j = chunkcoordintpair.z;
  180. diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
  181. index de2231bb0..ef4cdbcf5 100644
  182. --- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
  183. +++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
  184. @@ -62,15 +62,21 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
  185. }
  186.  
  187. @Nullable
  188. - private synchronized NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
  189. - NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(this.b.get(new ChunkCoordIntPair(i, j))); // Spigot
  190. + // Paper start - remove synchronized, manually sync on the map
  191. + private NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException {
  192. + Supplier<NBTTagCompound> supplier;
  193. + synchronized (this) {
  194. + supplier = this.b.get(new ChunkCoordIntPair(i, j));
  195. + }
  196. + NBTTagCompound nbttagcompound = SupplierUtils.getIfExists(supplier); // Spigot
  197. + // Paper end
  198.  
  199. return nbttagcompound != null ? nbttagcompound : this.b(generatoraccess, i, j);
  200. }
  201.  
  202. // CraftBukkit start
  203. private boolean check(ChunkProviderServer cps, int x, int z) throws IOException {
  204. - com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread");
  205. + //com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper
  206.  
  207. if (cps.isLoaded(x, z)) {
  208. return true;
  209. @@ -162,7 +168,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
  210. return null;
  211. }
  212.  
  213. - public synchronized Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException {
  214. + public Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException { // Paper - remove synchronize
  215. // CraftBukkit end
  216. NBTTagCompound nbttagcompound = this.a(generatoraccess, i, j);
  217.  
  218. diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
  219. index fcd9f5491..04939db83 100644
  220. --- a/src/main/java/net/minecraft/server/PlayerChunk.java
  221. +++ b/src/main/java/net/minecraft/server/PlayerChunk.java
  222. @@ -32,7 +32,7 @@ public class PlayerChunk {
  223. private boolean loadInProgress = false;
  224. private Runnable loadedRunnable = new Runnable() {
  225. public void run() {
  226. - loadInProgress = false;
  227. + loadInProgress = false; // Paper
  228. PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(location.x, location.z);
  229. markChunkUsed(); // Paper - delay chunk unloads
  230. }
  231. @@ -49,7 +49,8 @@ public class PlayerChunk {
  232. public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) {
  233. this.playerChunkMap = playerchunkmap;
  234. this.location = new ChunkCoordIntPair(i, j);
  235. - this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getOrLoadChunkAt(i, j);
  236. + loadInProgress = true;
  237. + this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getOrLoadChunkAt(i, j, loadedRunnable); // Paper
  238. this.chunkExists = this.chunk != null || ChunkIOExecutor.hasQueuedChunkLoad(playerChunkMap.getWorld(), i, j); // Paper
  239. markChunkUsed(); // Paper - delay chunk unloads
  240. }
  241. @@ -82,6 +83,7 @@ public class PlayerChunk {
  242.  
  243. this.c.remove(entityplayer);
  244. if (this.c.isEmpty()) {
  245. + if (!this.done) ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorld(), this.location.x, this.location.z, this.loadedRunnable); // Paper
  246. this.playerChunkMap.b(this);
  247. }
  248.  
  249. @@ -92,12 +94,14 @@ public class PlayerChunk {
  250. if (this.chunk != null) {
  251. return true;
  252. } else {
  253. - if (flag) {
  254. - this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z);
  255. - } else {
  256. - this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(this.location.x, this.location.z);
  257. + // Paper start
  258. + if (!loadInProgress) {
  259. + loadInProgress = true;
  260. + this.chunk = playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, loadedRunnable, flag);
  261. markChunkUsed(); // Paper - delay chunk unloads
  262. }
  263. + // Paper end
  264. +
  265.  
  266. return this.chunk != null;
  267. }
  268. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
  269. index 995e02f1d..a3e5c9830 100644
  270. --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
  271. +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
  272. @@ -159,13 +159,7 @@ public class CraftWorld implements World {
  273. // Paper start - Async chunk load API
  274. public void getChunkAtAsync(final int x, final int z, final ChunkLoadCallback callback) {
  275. final ChunkProviderServer cps = this.world.getChunkProviderServer();
  276. - callback.onLoad(cps.getChunkAt(x, z).bukkitChunk); // TODO: Add back async variant
  277. - /*cps.getChunkAt(x, z, new Runnable() {
  278. - @Override
  279. - public void run() {
  280. - callback.onLoad(cps.getChunkAt(x, z).bukkitChunk);
  281. - }
  282. - });*/
  283. + cps.getChunkAt(x, z, () -> callback.onLoad(cps.getChunkAt(x, z).bukkitChunk));
  284. }
  285.  
  286. public void getChunkAtAsync(Block block, ChunkLoadCallback callback) {
  287. @@ -266,7 +260,7 @@ public class CraftWorld implements World {
  288.  
  289. net.minecraft.server.Chunk chunk = null;
  290.  
  291. - chunk = Futures.getUnchecked(world.getChunkProviderServer().generateChunk(x, z));
  292. + chunk = MCUtil.processQueueWhileWaiting(world.getChunkProviderServer().generateChunk(x, z)); // Paper
  293. PlayerChunk playerChunk = world.getPlayerChunkMap().getChunk(x, z);
  294. if (playerChunk != null) {
  295. playerChunk.chunk = chunk;
  296. diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
  297. index 2bbd5a7e2..0b833ccae 100644
  298. --- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
  299. +++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
  300. @@ -6,11 +6,15 @@ import co.aikar.timings.Timing;
  301. import net.minecraft.server.Chunk;
  302. import net.minecraft.server.ChunkCoordIntPair;
  303. import net.minecraft.server.ChunkRegionLoader;
  304. +import net.minecraft.server.MCUtil;
  305. +import net.minecraft.server.MinecraftServer;
  306. import net.minecraft.server.NBTTagCompound;
  307.  
  308. import org.bukkit.Server;
  309. import org.bukkit.craftbukkit.util.AsynchronousExecutor;
  310.  
  311. +import java.util.concurrent.CompletableFuture;
  312. +import java.util.concurrent.ExecutionException;
  313. import java.util.concurrent.atomic.AtomicInteger;
  314.  
  315. class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChunk, Chunk, Runnable, RuntimeException> {
  316. @@ -21,13 +25,23 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
  317. try (Timing ignored = queuedChunk.provider.world.timings.chunkIOStage1.startTimingIfSync()) { // Paper
  318. ChunkRegionLoader loader = queuedChunk.loader;
  319. Object[] data = loader.loadChunk(queuedChunk.world, queuedChunk.x, queuedChunk.z, (chunk) -> {});
  320. -
  321. +
  322. if (data != null) {
  323. queuedChunk.compound = (NBTTagCompound) data[1];
  324. return (Chunk) data[0];
  325. + } else {
  326. + // Paper start
  327. + CompletableFuture<Chunk> chunkReady = new CompletableFuture<>();
  328. + MCUtil.ensureMain(() -> {
  329. + try {
  330. + queuedChunk.provider.generateChunk(queuedChunk.x, queuedChunk.z, chunkReady::complete);
  331. + } catch (Exception e) {
  332. + chunkReady.completeExceptionally(e);
  333. + }
  334. + });
  335. + return MCUtil.processQueueWhileWaiting(chunkReady);
  336. + // Paper end
  337. }
  338. -
  339. - return null;
  340. } catch (IOException ex) {
  341. throw new RuntimeException(ex);
  342. }
Add Comment
Please, Sign In to add comment