1+ package org .embeddedt .modernfix .forge .mixin .bugfix .chunk_deadlock ;
2+
3+ import net .minecraft .server .level .ChunkHolder ;
4+ import net .minecraft .server .level .ServerChunkCache ;
5+ import net .minecraft .world .level .ChunkPos ;
6+ import net .minecraft .world .level .chunk .ChunkAccess ;
7+ import net .minecraft .world .level .chunk .ChunkStatus ;
8+ import net .minecraft .world .level .chunk .LevelChunk ;
9+ import net .minecraftforge .fml .util .ObfuscationReflectionHelper ;
10+ import org .jetbrains .annotations .Nullable ;
11+ import org .spongepowered .asm .mixin .Mixin ;
12+ import org .spongepowered .asm .mixin .Shadow ;
13+ import org .spongepowered .asm .mixin .injection .At ;
14+ import org .spongepowered .asm .mixin .injection .Inject ;
15+ import org .spongepowered .asm .mixin .injection .callback .CallbackInfoReturnable ;
16+
17+ import java .lang .invoke .MethodHandle ;
18+ import java .lang .invoke .MethodHandles ;
19+ import java .lang .reflect .Field ;
20+
21+ @ Mixin (ServerChunkCache .class )
22+ public abstract class ServerChunkCache_CurrentLoadingMixin {
23+ @ Shadow @ Nullable protected abstract ChunkHolder getVisibleChunkIfPresent (long l );
24+
25+ private static final MethodHandle CURRENTLY_LOADING ;
26+
27+ static {
28+ try {
29+ Field currentlyLoadingField = ObfuscationReflectionHelper .findField (ChunkHolder .class , "currentlyLoading" );
30+ currentlyLoadingField .setAccessible (true );
31+ CURRENTLY_LOADING = MethodHandles .lookup ().unreflectGetter (currentlyLoadingField );
32+ } catch (Exception e ) {
33+ throw new RuntimeException ("Failed to get currentlyLoading field" , e );
34+ }
35+ }
36+
37+ /**
38+ * Check the currentlyLoading field before going to the future chain, as was done in 1.16. In 1.18 upstream seems
39+ * to have only applied this to getChunkNow().
40+ */
41+ @ Inject (method = "getChunk" , at = @ At (value = "INVOKE" , target = "Lnet/minecraft/server/level/ServerChunkCache;getChunkFutureMainThread(IILnet/minecraft/world/level/chunk/ChunkStatus;Z)Ljava/util/concurrent/CompletableFuture;" ), cancellable = true )
42+ private void checkCurrentlyLoading (int chunkX , int chunkZ , ChunkStatus requiredStatus , boolean load , CallbackInfoReturnable <ChunkAccess > cir ) {
43+ long i = ChunkPos .asLong (chunkX , chunkZ );
44+ ChunkHolder holder = this .getVisibleChunkIfPresent (i );
45+ if (holder != null ) {
46+ LevelChunk c ;
47+ try {
48+ c = (LevelChunk )CURRENTLY_LOADING .invokeExact (holder );
49+ } catch (Throwable e ) {
50+ e .printStackTrace ();
51+ c = null ;
52+ }
53+ if (c != null )
54+ cir .setReturnValue (c );
55+ }
56+ }
57+ }
0 commit comments