Skip to content

Commit bf4ce3a

Browse files
committed
clean code & fix leaks
1 parent 50ef43f commit bf4ce3a

File tree

6 files changed

+138
-161
lines changed

6 files changed

+138
-161
lines changed

src/main/java/me/mapacheee/extendedhorizons/integration/worldedit/WorldEditService.java

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
import com.sk89q.worldedit.WorldEditException;
1212
import com.sk89q.worldedit.util.eventbus.Subscribe;
1313
import com.thewinterframework.service.annotation.Service;
14+
import com.thewinterframework.utils.TimeUnit;
15+
import com.thewinterframework.service.annotation.scheduler.RepeatingTask;
1416
import com.thewinterframework.service.annotation.lifecycle.OnDisable;
1517
import com.thewinterframework.service.annotation.lifecycle.OnEnable;
1618
import me.mapacheee.extendedhorizons.ExtendedHorizonsPlugin;
17-
import me.mapacheee.extendedhorizons.shared.service.ConfigService;
1819
import me.mapacheee.extendedhorizons.shared.utils.ChunkUtils;
1920
import me.mapacheee.extendedhorizons.viewdistance.service.FakeChunkService;
2021
import org.bukkit.Bukkit;
@@ -25,7 +26,6 @@
2526
import java.util.Set;
2627
import java.util.UUID;
2728
import java.util.concurrent.ConcurrentHashMap;
28-
import java.util.concurrent.TimeUnit;
2929

3030
@Service
3131
public class WorldEditService {
@@ -48,7 +48,6 @@ public void onEnable() {
4848
try {
4949
WorldEdit.getInstance().getEventBus().register(this);
5050
enabled = true;
51-
startFlushTask();
5251
} catch (Throwable t) {
5352
plugin.getLogger().warning("[EH] Failed to register WorldEdit listener: " + t.getMessage());
5453
}
@@ -77,21 +76,20 @@ public void onEditSession(EditSessionEvent event) {
7776
event.setExtent(new ChunkTrackingExtent(event.getExtent(), world.getUID()));
7877
}
7978

80-
private void startFlushTask() {
81-
Bukkit.getAsyncScheduler().runAtFixedRate(plugin, (task) -> {
82-
if (modifiedChunks.isEmpty())
83-
return;
84-
85-
for (UUID worldId : new HashSet<>(modifiedChunks.keySet())) {
86-
Set<Long> keys = modifiedChunks.remove(worldId);
87-
if (keys != null && !keys.isEmpty()) {
88-
World world = Bukkit.getWorld(worldId);
89-
if (world != null) {
90-
fakeChunkService.refreshChunks(world, keys);
91-
}
79+
@RepeatingTask(every = 500, unit = TimeUnit.MILLIS, async = true)
80+
public void flushTask() {
81+
if (!enabled || modifiedChunks.isEmpty())
82+
return;
83+
84+
for (UUID worldId : new HashSet<>(modifiedChunks.keySet())) {
85+
Set<Long> keys = modifiedChunks.remove(worldId);
86+
if (keys != null && !keys.isEmpty()) {
87+
World world = Bukkit.getWorld(worldId);
88+
if (world != null) {
89+
fakeChunkService.refreshChunks(world, keys);
9290
}
9391
}
94-
}, 500L, 500L, TimeUnit.MILLISECONDS);
92+
}
9593
}
9694

9795
private class ChunkTrackingExtent extends AbstractDelegateExtent {
@@ -113,8 +111,8 @@ public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position,
113111
}
114112

115113
private void recordChange(BlockVector3 pos) {
116-
int chunkX = pos.getBlockX() >> 4;
117-
int chunkZ = pos.getBlockZ() >> 4;
114+
int chunkX = pos.x() >> 4;
115+
int chunkZ = pos.z() >> 4;
118116
long key = ChunkUtils.packChunkKey(chunkX, chunkZ);
119117

120118
modifiedChunks.computeIfAbsent(worldId, k -> ConcurrentHashMap.newKeySet()).add(key);

src/main/java/me/mapacheee/extendedhorizons/viewdistance/listener/BlockChangeListener.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,25 @@ public BlockChangeListener(ChunkLoaderService chunkLoaderService) {
2525

2626
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
2727
public void onBlockBreak(BlockBreakEvent event) {
28-
invalidate(event.getBlock().getChunk().getChunkKey());
28+
invalidate(event.getBlock().getWorld().getUID(), event.getBlock().getChunk().getChunkKey());
2929
}
3030

3131
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
3232
public void onBlockPlace(BlockPlaceEvent event) {
33-
invalidate(event.getBlock().getChunk().getChunkKey());
33+
invalidate(event.getBlock().getWorld().getUID(), event.getBlock().getChunk().getChunkKey());
3434
}
3535

3636
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
3737
public void onEntityExplode(EntityExplodeEvent event) {
38-
event.blockList().forEach(block -> invalidate(block.getChunk().getChunkKey()));
38+
event.blockList().forEach(block -> invalidate(block.getWorld().getUID(), block.getChunk().getChunkKey()));
3939
}
4040

4141
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
4242
public void onBlockExplode(BlockExplodeEvent event) {
43-
event.blockList().forEach(block -> invalidate(block.getChunk().getChunkKey()));
43+
event.blockList().forEach(block -> invalidate(block.getWorld().getUID(), block.getChunk().getChunkKey()));
4444
}
4545

46-
private void invalidate(long chunkKey) {
47-
chunkLoaderService.invalidateChunk(chunkKey);
46+
private void invalidate(java.util.UUID worldId, long chunkKey) {
47+
chunkLoaderService.invalidateChunk(worldId, chunkKey);
4848
}
4949
}

src/main/java/me/mapacheee/extendedhorizons/viewdistance/service/ChunkLoaderService.java

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.concurrent.ExecutorService;
2929
import java.util.concurrent.Executors;
3030
import java.util.concurrent.CompletableFuture;
31+
import me.mapacheee.extendedhorizons.viewdistance.service.cache.ChunkCacheKey;
3132
import java.util.concurrent.atomic.AtomicInteger;
3233
import java.util.concurrent.atomic.AtomicLong;
3334
import 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

Comments
 (0)