57
57
import net .minecraft .world .level .chunk .SingleValuePalette ;
58
58
import net .minecraft .world .level .entity .PersistentEntitySectionManager ;
59
59
import org .apache .logging .log4j .Logger ;
60
- import org .bukkit .Bukkit ;
61
60
import org .bukkit .craftbukkit .v1_20_R2 .CraftChunk ;
62
61
63
62
import javax .annotation .Nonnull ;
79
78
import java .util .Map ;
80
79
import java .util .Optional ;
81
80
import java .util .concurrent .CompletableFuture ;
81
+ import java .util .concurrent .ExecutionException ;
82
82
import java .util .concurrent .Semaphore ;
83
- import java .util .concurrent .TimeUnit ;
84
- import java .util .concurrent .TimeoutException ;
85
83
import java .util .function .IntFunction ;
86
84
87
85
import static java .lang .invoke .MethodType .methodType ;
@@ -276,12 +274,49 @@ static DelegateSemaphore applyLock(LevelChunkSection section) {
276
274
}
277
275
}
278
276
} catch (Throwable e ) {
279
- e . printStackTrace ( );
277
+ LOGGER . error ( "Error apply DelegateSemaphore" , e );
280
278
throw new RuntimeException (e );
281
279
}
282
280
}
283
281
284
- public static LevelChunk ensureLoaded (ServerLevel serverLevel , int chunkX , int chunkZ ) {
282
+ public static CompletableFuture <LevelChunk > ensureLoaded (ServerLevel serverLevel , int chunkX , int chunkZ ) {
283
+ LevelChunk levelChunk = getChunkImmediatelyAsync (serverLevel , chunkX , chunkZ );
284
+ if (levelChunk != null ) {
285
+ return CompletableFuture .completedFuture (levelChunk );
286
+ }
287
+ if (PaperLib .isPaper ()) {
288
+ CompletableFuture <LevelChunk > future = serverLevel
289
+ .getWorld ()
290
+ .getChunkAtAsync (chunkX , chunkZ , true , true )
291
+ .thenApply (chunk -> {
292
+ addTicket (serverLevel , chunkX , chunkZ );
293
+ try {
294
+ return (LevelChunk ) CRAFT_CHUNK_GET_HANDLE .invoke (chunk );
295
+ } catch (Throwable e ) {
296
+ LOGGER .error ("Could not asynchronously load chunk at {},{}" , chunkX , chunkZ , e );
297
+ return null ;
298
+ }
299
+ });
300
+ try {
301
+ if (!future .isCompletedExceptionally () || (future .isDone () && future .get () != null )) {
302
+ return future ;
303
+ }
304
+ Throwable t = future .exceptionNow ();
305
+ LOGGER .error ("Asynchronous chunk load at {},{} exceptionally completed immediately" , chunkX , chunkZ , t );
306
+ } catch (InterruptedException | ExecutionException e ) {
307
+ LOGGER .error (
308
+ "Unexpected error when getting completed future at chunk {},{}. Returning to default." ,
309
+ chunkX ,
310
+ chunkZ ,
311
+ e
312
+ );
313
+ }
314
+ }
315
+ return CompletableFuture .supplyAsync (() -> TaskManager .taskManager ().sync (() -> serverLevel .getChunk (chunkX , chunkZ )));
316
+ }
317
+
318
+
319
+ public static @ Nullable LevelChunk getChunkImmediatelyAsync (ServerLevel serverLevel , int chunkX , int chunkZ ) {
285
320
if (!PaperLib .isPaper ()) {
286
321
LevelChunk nmsChunk = serverLevel .getChunkSource ().getChunk (chunkX , chunkZ , false );
287
322
if (nmsChunk != null ) {
@@ -290,6 +325,7 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
290
325
if (Fawe .isMainThread ()) {
291
326
return serverLevel .getChunk (chunkX , chunkZ );
292
327
}
328
+ return null ;
293
329
} else {
294
330
LevelChunk nmsChunk = serverLevel .getChunkSource ().getChunkAtIfCachedImmediately (chunkX , chunkZ );
295
331
if (nmsChunk != null ) {
@@ -305,30 +341,8 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
305
341
if (Fawe .isMainThread ()) {
306
342
return serverLevel .getChunk (chunkX , chunkZ );
307
343
}
308
- CompletableFuture <org .bukkit .Chunk > future = serverLevel .getWorld ().getChunkAtAsync (chunkX , chunkZ , true , true );
309
- try {
310
- CraftChunk chunk ;
311
- try {
312
- chunk = (CraftChunk ) future .get (10 , TimeUnit .SECONDS );
313
- } catch (TimeoutException e ) {
314
- String world = serverLevel .getWorld ().getName ();
315
- // We've already taken 10 seconds we can afford to wait a little here.
316
- boolean loaded = TaskManager .taskManager ().sync (() -> Bukkit .getWorld (world ) != null );
317
- if (loaded ) {
318
- LOGGER .warn ("Chunk {},{} failed to load in 10 seconds in world {}. Retrying..." , chunkX , chunkZ , world );
319
- // Retry chunk load
320
- chunk = (CraftChunk ) serverLevel .getWorld ().getChunkAtAsync (chunkX , chunkZ , true , true ).get ();
321
- } else {
322
- throw new UnsupportedOperationException ("Cannot load chunk from unloaded world " + world + "!" );
323
- }
324
- }
325
- addTicket (serverLevel , chunkX , chunkZ );
326
- return (LevelChunk ) CRAFT_CHUNK_GET_HANDLE .invoke (chunk );
327
- } catch (Throwable e ) {
328
- e .printStackTrace ();
329
- }
344
+ return null ;
330
345
}
331
- return TaskManager .taskManager ().sync (() -> serverLevel .getChunk (chunkX , chunkZ ));
332
346
}
333
347
334
348
private static void addTicket (ServerLevel serverLevel , int chunkX , int chunkZ ) {
@@ -672,7 +686,7 @@ static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
672
686
}
673
687
methodremoveTickingBlockEntity .invoke (levelChunk , beacon .getBlockPos ());
674
688
} catch (Throwable throwable ) {
675
- throwable . printStackTrace ( );
689
+ LOGGER . error ( "Error removing beacon" , throwable );
676
690
}
677
691
}
678
692
0 commit comments