/
minecraftbackup
/
AnarchyExploitFixes
Обзор
Документация
Войти
/
minecraftbackup
/
AnarchyExploitFixes
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/DroppedItemLimit.java
169 строк
8 KB
kumorio
Prevent "Plugin is getting a faraway chunk" spam when players are at … (#238)
02 окт 2024, 11:42
Не верифицирован
02 окт 2024, 11:42
1f7ebc5
Код
Авторство
О чём код?
package me.xginko.aef.modules.chunklimits; import com.cryptomorin.xseries.XEntityType; import com.destroystokyo.paper.MaterialTags; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.LocationUtil; import me.xginko.aef.utils.models.ChunkUID; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.world.ChunkLoadEvent; import java.time.Duration; import java.util.EnumSet; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; public class DroppedItemLimit extends AEFModule implements Consumer<ScheduledTask>, Listener { private ScheduledTask scheduledTask; private final Cache<ChunkUID, ScheduledTask> scheduledChecks; private final Set<Material> whitelistedTypes; private final long checkPeriod, cleanupDelay; private final int maxDroppedItemsPerChunk; private final boolean logIsEnabled, usingWhitelist, onChunkLoad; public DroppedItemLimit() { super("chunk-limits.entity-limits.dropped-item-limit"); config.addComment(configPath + ".enable", """ Limit the amount of dropped items in a chunk to combat lag.\s Be aware this does not prioritize items by value or anything,\s it just deletes whatever happens to get over the limit during\s counting."""); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", true); this.maxDroppedItemsPerChunk = config.getInt(configPath + ".max-dropped-items-per-chunk", 200); this.cleanupDelay = Math.max(1, config.getInt(configPath + ".post-item-drop-check-delay-ticks", 60, """ The delay in ticks the plugin will wait after an item in a chunk\s has dropped before the check logic will run.\s This improves performance as there will be no check for each single\s item entity that spawns.""")); this.checkPeriod = config.getInt(configPath + ".check-period-in-ticks", 1200, """ The period in ticks in which all loaded chunks should be regularly\s checked. Keep in mind: A lower number provides more accuracy but is\s also worse for performance."""); this.scheduledChecks = Caffeine.newBuilder().expireAfterWrite(Duration.ofMillis(cleanupDelay * 50L)).build(); this.onChunkLoad = config.getBoolean(configPath + ".check-on-chunk-load", true, """ Runs item check when a chunk is loaded."""); this.usingWhitelist = config.getBoolean(configPath + ".whitelist-specific-item-types", false); this.whitelistedTypes = config.getList(configPath + ".whitelisted-types", MaterialTags.SHULKER_BOXES.getValues().stream().map(Enum::name).sorted().toList(), """ Check the paper api for correct Material enums:\s https://jd.papermc.io/paper/1.20.6/org/bukkit/Material.html\s Make sure your minecraft version is matching as well.""") .stream() .map(configuredType -> { try { return Material.valueOf(configuredType); } catch (IllegalArgumentException e) { notRecognized(Material.class, configuredType); return null; } }) .filter(Objects::nonNull) .collect(Collectors.toCollection(() -> EnumSet.noneOf(Material.class))); } @Override public void enable() { plugin.getServer().getPluginManager().registerEvents(this, plugin); this.scheduledTask = plugin.getServer().getGlobalRegionScheduler() .runAtFixedRate(plugin, this, checkPeriod, checkPeriod); } @Override public boolean shouldEnable() { return config.getBoolean(configPath + ".enable", false); } @Override public void disable() { HandlerList.unregisterAll(this); if (scheduledTask != null) scheduledTask.cancel(); scheduledChecks.asMap().forEach((chunk, queuedCheck) -> queuedCheck.cancel()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onItemDrop(ItemSpawnEvent event) { Chunk chunk = event.getEntity().getChunk(); ChunkUID chunkUID = ChunkUID.of(chunk); // Don't create a check task for each spawning item scheduledChecks.get(chunkUID, k -> plugin.getServer().getRegionScheduler().runDelayed(plugin, chunk.getWorld(), chunk.getX(), chunk.getZ(), chunkCheck -> { if (!chunk.isEntitiesLoaded()) return; int droppedItemCount = 0; for (Entity entity : chunk.getEntities()) { if (entity.getType() != XEntityType.ITEM.get()) continue; droppedItemCount++; if (droppedItemCount <= maxDroppedItemsPerChunk) continue; if (usingWhitelist && whitelistedTypes.contains(((Item) entity).getItemStack().getType())) continue; entity.remove(); if (logIsEnabled) info("Removed dropped item at " + LocationUtil.toString(entity.getLocation()) + " because reached limit of " + maxDroppedItemsPerChunk); } }, cleanupDelay)); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onChunkLoad(ChunkLoadEvent event) { if (!onChunkLoad || event.isNewChunk()) return; if (event.getChunk().getX() > 1875000 || event.getChunk().getZ() > 1875000 || event.getChunk().getX() < -1875000 || event.getChunk().getZ() < -1875000) return; int droppedItemCount = 0; for (Entity entity : event.getChunk().getEntities()) { if (entity.getType() != XEntityType.ITEM.get()) continue; droppedItemCount++; if (droppedItemCount <= maxDroppedItemsPerChunk) continue; if (usingWhitelist && whitelistedTypes.contains(((Item) entity).getItemStack().getType())) continue; entity.remove(); if (logIsEnabled) info("Removed dropped item at " + LocationUtil.toString(entity.getLocation()) + " because reached limit of " + maxDroppedItemsPerChunk); } } @Override public void accept(ScheduledTask task) { for (World world : plugin.getServer().getWorlds()) { for (Chunk chunk : world.getLoadedChunks()) { plugin.getServer().getRegionScheduler().execute(plugin, world, chunk.getX(), chunk.getZ(), () -> { if (!chunk.isEntitiesLoaded()) return; AtomicInteger droppedItemCount = new AtomicInteger(); for (Entity entity : chunk.getEntities()) { entity.getScheduler().execute(plugin, () -> { if (entity.getType() != XEntityType.ITEM.get()) return; if (droppedItemCount.incrementAndGet() <= maxDroppedItemsPerChunk) return; if (usingWhitelist && whitelistedTypes.contains(((Item) entity).getItemStack().getType())) return; entity.remove(); if (logIsEnabled) info("Removed dropped item at " + LocationUtil.toString(entity.getLocation()) + " because reached limit of " + maxDroppedItemsPerChunk); }, null, 1L); } }); } } } }