Skip to content

Commit

Permalink
cache blocklimiter result to prevent lag
Browse files Browse the repository at this point in the history
  • Loading branch information
xGinko committed Dec 31, 2024
1 parent 2175d87 commit 8e5669e
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package me.xginko.aef.modules.chunklimits;

import com.cryptomorin.xseries.XMaterial;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.github.thatsmusic99.configurationmaster.api.ConfigSection;
import me.xginko.aef.modules.AEFModule;
import org.bukkit.Chunk;
Expand All @@ -12,16 +14,21 @@
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;

import java.time.Duration;
import java.util.EnumMap;
import java.util.Map;
import java.util.TreeMap;

public class BlockLimit extends AEFModule implements Listener {

private final Map<Material, Integer> blockLimits = new EnumMap<>(Material.class);
private final long materialCountCacheMillis;

private Cache<Chunk, Cache<Material, Integer>> chunkMaterialCache;

public BlockLimit() {
super("chunk-limits.block-limit", false);
this.materialCountCacheMillis = config.getLong(configPath + ".material-count-cache-millis", 5000);

Map<XMaterial, Integer> universal = new EnumMap<>(XMaterial.class);
universal.put(XMaterial.ENCHANTING_TABLE, 16);
Expand Down Expand Up @@ -144,12 +151,22 @@ public BlockLimit() {

@Override
public void enable() {
chunkMaterialCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}

@Override
public void disable() {
HandlerList.unregisterAll(this);
if (chunkMaterialCache != null) {
for (Map.Entry<Chunk, Cache<Material, Integer>> entry : chunkMaterialCache.asMap().entrySet()) {
entry.getValue().invalidateAll();
entry.getValue().cleanUp();
}
chunkMaterialCache.invalidateAll();
chunkMaterialCache.cleanUp();
chunkMaterialCache = null;
}
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
Expand All @@ -170,24 +187,30 @@ && exceedsPerChunkLimit(event.getMaterial(), event.getPlayer().getChunk())) {
}
}

private boolean exceedsPerChunkLimit(Material material, Chunk chunk) {
final int materialLimit = blockLimits.get(material);
private boolean exceedsPerChunkLimit(Material blockType, Chunk chunk) {
final int minY = chunk.getWorld().getMinHeight();
final int maxY = chunk.getWorld().getMaxHeight();

int count = 0;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = minY; y < maxY; y++) {
if (chunk.getBlock(x, y, z).getType() == material) {
count++;
if (count > materialLimit) {
return true;
Cache<Material, Integer> materialCountCache = chunkMaterialCache.getIfPresent(chunk);
if (materialCountCache == null) {
materialCountCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(materialCountCacheMillis)).build();
}

Integer materialCount = materialCountCache.get(blockType, material -> {
int count = 0;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = minY; y < maxY; y++) {
if (chunk.getBlock(x, y, z).getType() == material) {
count++;
}
}
}
}
}
return false;
return count;
});

chunkMaterialCache.put(chunk, materialCountCache);
return materialCount > blockLimits.get(blockType);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package me.xginko.aef.modules.chunklimits;

import com.cryptomorin.xseries.XMaterial;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.github.thatsmusic99.configurationmaster.api.ConfigSection;
import me.xginko.aef.modules.AEFModule;
import me.xginko.aef.utils.WorldUtil;
Expand All @@ -14,16 +16,21 @@
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;

import java.time.Duration;
import java.util.EnumMap;
import java.util.Map;
import java.util.TreeMap;

public class BlockLimit extends AEFModule implements Listener {

private final Map<Material, Integer> blockLimits = new EnumMap<>(Material.class);
private final long materialCountCacheMillis;

private Cache<Chunk, Cache<Material, Integer>> chunkMaterialCache;

public BlockLimit() {
super("chunk-limits.block-limit", false);
this.materialCountCacheMillis = config.getLong(configPath + ".material-count-cache-millis", 5000);

Map<XMaterial, Integer> universal = new EnumMap<>(XMaterial.class);
universal.put(XMaterial.ENCHANTING_TABLE, 16);
Expand Down Expand Up @@ -146,12 +153,22 @@ public BlockLimit() {

@Override
public void enable() {
chunkMaterialCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(1)).build();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}

@Override
public void disable() {
HandlerList.unregisterAll(this);
if (chunkMaterialCache != null) {
for (Map.Entry<Chunk, Cache<Material, Integer>> entry : chunkMaterialCache.asMap().entrySet()) {
entry.getValue().invalidateAll();
entry.getValue().cleanUp();
}
chunkMaterialCache.invalidateAll();
chunkMaterialCache.cleanUp();
chunkMaterialCache = null;
}
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
Expand All @@ -172,23 +189,30 @@ && exceedsPerChunkLimit(event.getMaterial(), event.getPlayer().getChunk())) {
}
}

private boolean exceedsPerChunkLimit(Material material, Chunk chunk) {
final int materialLimit = blockLimits.get(material);
private boolean exceedsPerChunkLimit(Material blockType, Chunk chunk) {
final int minY = WorldUtil.getMinWorldHeight(chunk.getWorld());
final int maxY = chunk.getWorld().getMaxHeight();
int count = 0;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = minY; y < maxY; y++) {
if (chunk.getBlock(x, y, z).getType() == material) {
count++;
if (count > materialLimit) {
return true;

Cache<Material, Integer> materialCountCache = chunkMaterialCache.getIfPresent(chunk);
if (materialCountCache == null) {
materialCountCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(materialCountCacheMillis)).build();
}

Integer materialCount = materialCountCache.get(blockType, material -> {
int count = 0;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = minY; y < maxY; y++) {
if (chunk.getBlock(x, y, z).getType() == material) {
count++;
}
}
}
}
}
return false;
return count;
});

chunkMaterialCache.put(chunk, materialCountCache);
return materialCount > blockLimits.get(blockType);
}
}

0 comments on commit 8e5669e

Please sign in to comment.