2828import java .util .concurrent .ExecutorService ;
2929import java .util .concurrent .Executors ;
3030import java .util .concurrent .CompletableFuture ;
31+ import me .mapacheee .extendedhorizons .viewdistance .service .cache .ChunkCacheKey ;
3132import java .util .concurrent .atomic .AtomicInteger ;
3233import java .util .concurrent .atomic .AtomicLong ;
3334import me .mapacheee .extendedhorizons .shared .config .MainConfig ;
@@ -47,7 +48,7 @@ public class ChunkLoaderService {
4748
4849 private final Map <Long , Long > generatingChunks = new ConcurrentHashMap <>();
4950 private final ExecutorService chunkProcessor ;
50- private final Map <Long , Object > chunkMemoryCache ;
51+ private final Map <ChunkCacheKey , Object > chunkMemoryCache ;
5152
5253 private final AtomicLong memoryCacheHits = new AtomicLong (0 );
5354 private final AtomicLong memoryCacheMisses = new AtomicLong (0 );
@@ -78,9 +79,9 @@ public ChunkLoaderService(
7879 int maxCacheSize = configService .get ().performance ().fakeChunks ().maxMemoryCacheSize ();
7980
8081 this .chunkMemoryCache = Collections .synchronizedMap (
81- new LinkedHashMap <Long , Object >(16 , 0.75f , true ) {
82+ new LinkedHashMap <ChunkCacheKey , Object >(16 , 0.75f , true ) {
8283 @ Override
83- protected boolean removeEldestEntry (Map .Entry <Long , Object > eldest ) {
84+ protected boolean removeEldestEntry (Map .Entry <ChunkCacheKey , Object > eldest ) {
8485 return size () > maxCacheSize ;
8586 }
8687 });
@@ -169,7 +170,7 @@ public void processChunkBatch(Player player, List<Long> batch, Set<Long> sentTra
169170 }
170171
171172 // Strategy 1: Memory cache
172- Object memoryChunk = getChunkFromMemoryCache (w , chunkX , chunkZ );
173+ Object memoryChunk = getChunkFromMemoryCache (w . getUID () , chunkX , chunkZ );
173174 if (memoryChunk != null ) {
174175 if (DEBUG ) {
175176 logger .info ("[EH] Loaded chunk {},{} from memory cache" , chunkX , chunkZ );
@@ -378,7 +379,7 @@ private void generateChunkAndSend(Player player, World world, int chunkX, int ch
378379 if (DEBUG )
379380 logger .info ("[EH] Generated chunk {},{}" , chunkX , chunkZ );
380381 long chunkKey = ChunkUtils .packChunkKey (chunkX , chunkZ );
381- cacheChunkInMemory (chunkKey , nmsChunk );
382+ cacheChunkInMemory (chunk . getWorld (). getUID (), chunkKey , nmsChunk );
382383 sendChunkPacket (p , nmsChunk , key , sentTracker ,
383384 FakeChunkLoadEvent .LoadSource .GENERATED , borderCenterX , borderCenterZ , borderSize );
384385 } else {
@@ -398,22 +399,29 @@ private void generateChunkAndSend(Player player, World world, int chunkX, int ch
398399 });
399400 }
400401
401- private Object getChunkFromMemoryCache (World world , int chunkX , int chunkZ ) {
402+ private Object getChunkFromMemoryCache (UUID worldId , int chunkX , int chunkZ ) {
402403 if (!configService .get ().performance ().fakeChunks ().enableMemoryCache ()) {
403404 return null ;
404405 }
405406 long chunkKey = ChunkUtils .packChunkKey (chunkX , chunkZ );
407+ ChunkCacheKey cacheKey = new ChunkCacheKey (worldId , chunkKey );
408+
406409 synchronized (chunkMemoryCache ) {
407- Object cached = chunkMemoryCache .get (chunkKey );
410+ Object cached = chunkMemoryCache .get (cacheKey );
408411 if (cached != null ) {
409412 memoryCacheHits .incrementAndGet ();
410413 return cached ;
411414 }
412415 }
416+
417+ World world = Bukkit .getWorld (worldId );
418+ if (world == null )
419+ return null ;
420+
413421 try {
414422 Object chunk = nmsChunkAccess .getChunkIfLoaded (world , chunkX , chunkZ );
415423 if (chunk != null ) {
416- cacheChunkInMemory (chunkKey , chunk );
424+ cacheChunkInMemory (worldId , chunkKey , chunk );
417425 memoryCacheHits .incrementAndGet ();
418426 return chunk ;
419427 }
@@ -425,11 +433,12 @@ private Object getChunkFromMemoryCache(World world, int chunkX, int chunkZ) {
425433 return null ;
426434 }
427435
428- private void cacheChunkInMemory (long chunkKey , Object chunk ) {
436+ private void cacheChunkInMemory (UUID worldId , long chunkKey , Object chunk ) {
429437 if (!configService .get ().performance ().fakeChunks ().enableMemoryCache ())
430438 return ;
439+ ChunkCacheKey key = new ChunkCacheKey (worldId , chunkKey );
431440 synchronized (chunkMemoryCache ) {
432- chunkMemoryCache .put (chunkKey , chunk );
441+ chunkMemoryCache .put (key , chunk );
433442 }
434443 }
435444
@@ -578,9 +587,10 @@ public int getMemoryCacheSize() {
578587 return chunkMemoryCache .size ();
579588 }
580589
581- public void invalidateChunk (long chunkKey ) {
582- if (chunkMemoryCache .containsKey (chunkKey )) {
583- chunkMemoryCache .remove (chunkKey );
590+ public void invalidateChunk (UUID worldId , long chunkKey ) {
591+ ChunkCacheKey key = new ChunkCacheKey (worldId , chunkKey );
592+ if (chunkMemoryCache .containsKey (key )) {
593+ chunkMemoryCache .remove (key );
584594 if (DEBUG ) {
585595 int x = ChunkUtils .unpackX (chunkKey );
586596 int z = ChunkUtils .unpackZ (chunkKey );
@@ -589,6 +599,17 @@ public void invalidateChunk(long chunkKey) {
589599 }
590600 }
591601
602+ public void invalidateWorld (UUID worldId ) {
603+ int initialSize = chunkMemoryCache .size ();
604+ synchronized (chunkMemoryCache ) {
605+ chunkMemoryCache .keySet ().removeIf (key -> key .worldId ().equals (worldId ));
606+ }
607+ int removed = initialSize - chunkMemoryCache .size ();
608+ if (removed > 0 ) {
609+ logger .info ("[EH] Invalidated {} chunks for world {}" , removed , worldId );
610+ }
611+ }
612+
592613 public double getCacheHitRate () {
593614 long hits = memoryCacheHits .get ();
594615 long misses = memoryCacheMisses .get ();
0 commit comments