/
minecraftbackup
/
AnarchyExploitFixes
Обзор
Документация
Войти
/
minecraftbackup
/
AnarchyExploitFixes
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/modules/chunklimits/VillagerLimit.java
166 строк
7 KB
Ginko
2.7.2 release (#233)
13 авг 2024, 08:21
Не верифицирован
13 авг 2024, 08:21
d20da6e
Код
Авторство
О чём код?
package me.xginko.aef.modules.chunklimits; import com.cryptomorin.xseries.XEntityType; import io.papermc.paper.threadedregions.scheduler.ScheduledTask; import me.xginko.aef.modules.AEFModule; import me.xginko.aef.utils.LocationUtil; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Villager; 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.CreatureSpawnEvent; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; public class VillagerLimit extends AEFModule implements Consumer<ScheduledTask>, Listener { private ScheduledTask scheduledTask; private final List<Villager.Profession> removalPriority; private final Set<Villager.Profession> professionWhitelist; private final long checkPeriod; private final int maxVillagersPerChunk; private final boolean logIsEnabled, whitelistEnabled; public VillagerLimit() { super("chunk-limits.entity-limits.villager-limit"); this.maxVillagersPerChunk = Math.max(1, config.getInt(configPath + ".max-villagers-per-chunk", 25)); this.logIsEnabled = config.getBoolean(configPath + ".log-removals", false); this.checkPeriod = Math.max(config.getInt(configPath + ".check-period-in-ticks", 600, "Check all chunks every x ticks."), 1); final List<String> defPriority = Stream.of("NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER", "FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN") .filter(prof -> { try { Villager.Profession.valueOf(prof); return true; } catch (IllegalArgumentException e) { return false; } }) .collect(Collectors.toList()); this.removalPriority = config.getList(configPath + ".removal-priority", defPriority, """ Professions that are in the top of the list are going to be scheduled for\s removal first.""") .stream() .map(configuredProfession -> { try { return Villager.Profession.valueOf(configuredProfession); } catch (IllegalArgumentException e) { notRecognized(Villager.Profession.class, configuredProfession); return null; } }) .filter(Objects::nonNull) .toList(); final List<String> defWhitelist = Stream.of("NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER", "FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN") .filter(prof -> { try { Villager.Profession.valueOf(prof); return true; } catch (IllegalArgumentException e) { return false; } }) .collect(Collectors.toList()); this.whitelistEnabled = config.getBoolean(configPath + ".whitelist.enable", false); this.professionWhitelist = config.getList(configPath + ".whitelist.professions", defWhitelist) .stream() .map(configuredProfession -> { try { return Villager.Profession.valueOf(configuredProfession); } catch (IllegalArgumentException e) { notRecognized(Villager.Profession.class, configuredProfession); return null; } }) .filter(Objects::nonNull) .collect(Collectors.toCollection(HashSet::new)); } @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(); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onCreatureSpawn(CreatureSpawnEvent event) { if (event.getEntityType().equals(XEntityType.VILLAGER.get())) { this.checkVillagersInChunk(event.getEntity().getChunk()); } } @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()) { this.checkVillagersInChunk(chunk); } }); } } } private void checkVillagersInChunk(Chunk chunk) { final Entity[] entities = chunk.getEntities(); if (entities.length <= maxVillagersPerChunk) return; // Create a list with all villagers in that chunk final List<Villager> villagers_in_chunk = new ArrayList<>(); for (Entity entity : entities) { if (entity.getType() == XEntityType.VILLAGER.get()) { Villager villager = (Villager) entity; if (whitelistEnabled && !professionWhitelist.contains(villager.getProfession())) { villagers_in_chunk.add(villager); } } } // Check if there are more villagers in that chunk than allowed final int amount_over_the_limit = villagers_in_chunk.size() - maxVillagersPerChunk; if (amount_over_the_limit <= 0) return; // Sort villager list by profession priority villagers_in_chunk.sort(Comparator.comparingInt(villager -> { final Villager.Profession profession = villager.getProfession(); return removalPriority.contains(profession) ? removalPriority.indexOf(profession) : Integer.MAX_VALUE; })); // Remove prioritized villagers that are too many for (int i = 0; i < amount_over_the_limit; i++) { Villager villager = villagers_in_chunk.get(i); villager.getScheduler().execute(plugin, () -> { villager.remove(); if (logIsEnabled) info("Removed villager with profession '" + villager.getProfession() + "' at " + LocationUtil.toString(villager.getLocation())); }, null, 1L); } } }