package cx.sfy.LagAssist.chunks; import java.util.HashMap; import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import cx.sfy.LagAssist.Main; import cx.sfy.LagAssist.utils.Cache; public class ChkLimiter implements Listener { private static Cache entcache = new Cache(30); private static Cache tilecache = new Cache(100); private static int moblimit = -1; private static int tilelimit = -1; public static void Enabler(boolean reload) { if (!reload) { Main.p.getServer().getPluginManager().registerEvents(new ChkLimiter(), Main.p); runTask(); } Bukkit.getLogger().info(" §e[§a✔§e] §fChunk Limiter."); moblimit = Main.config.getInt("limiter.mobs.total-limit"); tilelimit = Main.config.getInt("limiter.tiles.total-limit"); } static int i = 0; private static void runTask() { Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.p, () -> { i++; if (i % Main.config.getInt("limiter.timer-time") == 0) { for (World w : Bukkit.getWorlds()) { for (Chunk chk : w.getLoadedChunks()) { Map counts = new HashMap(); for (Entity ent : chk.getEntities()) { EntityType type = ent.getType(); int allowed = getMobMaxHard(type); if (allowed == -1) { continue; } int count = counts.getOrDefault(ent.getType(), 0); // Over 30 bye if (count < allowed) { counts.put(type, count + 1); continue; } ent.remove(); } } } } tilecache.tick(); entcache.tick(); }, 1L, 1L); } private static int getMobMaxHard(EntityType entype) { String location = "limiter.mobs.hard-limit." + entype.toString().toLowerCase(); if (Main.config.contains(location)) { return Main.config.getInt(location); } return -1; } private static int getMobMaxSoft(EntityType entype) { String location = "limiter.mobs.soft-limit." + entype.toString().toLowerCase(); if (Main.config.contains(location)) { return Main.config.getInt(location); } return -1; } private static int getMobMaxSoft(Entity ent) { return getMobMaxSoft(ent.getType()); } private static int getTileMax(Class cls) { String location = "limiter.tiles.per-limit." + cls.getSimpleName().toLowerCase(); if (Main.config.contains(location)) { return Main.config.getInt(location); } return -1; } private static int getTileMax(Block b) { return getTileMax(b.getState().getClass()); } private static int getMobCount(Chunk chk, EntityType entype) { int ents = 0; if (!entcache.isCached(chk)) { entcache.putCached(chk, chk.getEntities()); } for (Entity ent : entcache.getCached(chk)) { if (ent == null) { continue; } if (ent.getType() != entype) { continue; } ents++; } return ents; } private static int getMobCount(Chunk chk) { return chk.getEntities().length; } private static int getTileCount(Chunk chk, Class type) { int tls = 0; if (!tilecache.isCached(chk)) { tilecache.putCached(chk, chk.getTileEntities()); } for (BlockState tle : tilecache.getCached(chk)) { if (tle == null) { continue; } if (!tle.getClass().equals(type)) { continue; } tls++; } return tls; } private static int getTileCount(Chunk chk) { return chk.getTileEntities().length; } // VERIFIERS (CODE QUALITY IMPROVERS) private static boolean isDeniedMob(Entity ent) { EntityType etype = ent.getType(); // Fix issues with destroying player objects. if (etype == EntityType.PLAYER) { return false; } Chunk chk = ent.getLocation().getChunk(); int current = getMobCount(chk, etype); int maximum = getMobMaxSoft(ent); if (maximum < 0) { current = getMobCount(chk); maximum = moblimit; } if (maximum < 0) { return false; } if (current < maximum) { return false; } return true; } private static boolean isDeniedTile(Block b) { Chunk chk = b.getLocation().getChunk(); Class type = b.getState().getClass(); String typename = type.getSimpleName().toLowerCase(); Main.sendDebug("isDeniedTile: " + typename, 1); if (typename.equals("craftblockstate")) { return false; } int current = getTileCount(chk, type); int maximum = getTileMax(b); if (maximum < 0) { current = getTileCount(chk); maximum = tilelimit; } if (maximum < 0) { return false; } if (current < maximum) { return false; } return true; } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onVehicleSpawn(VehicleCreateEvent e) { Vehicle ent = e.getVehicle(); // 1.8 doesn't support cancel. Fuk if (isDeniedMob(ent)) { ent.remove(); } } @EventHandler(priority = EventPriority.LOWEST) public void onSpawn(EntitySpawnEvent e) { if (e.isCancelled()) { return; } Entity ent = e.getEntity(); e.setCancelled(isDeniedMob(ent)); } @EventHandler(priority = EventPriority.LOWEST) public void onPlace(BlockPlaceEvent e) { if (e.isCancelled()) { return; } Block b = e.getBlock(); e.setCancelled(isDeniedTile(b)); } }