• 【问卷调查奖励发放公告】

    感谢大家积极参与本次 MineBBS 社区问卷调查。200 金粒的参与奖励已完成发放。部分用户发放失败,请【点击此处】 查看详情。

资源图标

原创 开源 工具 EntityLimiter —— 掉落物自动清理和实体区块数量限制 2.0

请登录后获取
版权类型
原创
插件中文名称
自动清理和区块实体限制
插件英文名称
EntityLimiter
原帖地址
#
支持的核心(服务端)
  1. Paper
语言支持
中文(简体)
前置组件
适配版本(Java)
  1. 1.21
QQ20250211-055944.png

这是我用DeepSeek写出来的插件
功能一:自定义分钟清理一次全局掉落物,清理前有倒计时提示。
功能二:自定义限制单个区块内实体数量,超出的清除
指令:
手动掉落物清理:/clearloot
手动实体清理:/entitylimiter runnow
重载配置:/entitylimiter reload
代码:
Java:
package MyPlugin.entityLimiter;

import org.bukkit.*;
import org.bukkit.command.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.*;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.*;

public class EntityLimiter extends JavaPlugin {
    private Map<EntityType, Integer> entityLimits = new HashMap<>();
    private int entityTaskId = -1;
    private int itemCleanTaskId = -1;

    // ========== 插件生命周期 ==========
    @Override
    public void onEnable() {
        saveDefaultConfig();
        loadConfig();
        startSchedulers();
        registerCommands();
    }

    @Override
    public void onDisable() {
        cancelTasks();
    }

    // ========== 配置加载 ==========
    private void loadConfig() {
        reloadConfig();
        FileConfiguration config = getConfig();

        // 加载实体限制配置
        entityLimits.clear();
        config.getConfigurationSection("entities").getKeys(false).forEach(key -> {
            try {
                EntityType type = EntityType.valueOf(key.toUpperCase());
                entityLimits.put(type, config.getInt("entities." + key));
            } catch (IllegalArgumentException e) {
                getLogger().warning("无效的实体类型: " + key);
            }
        });
    }

    // ========== 任务调度 ==========
    private void startSchedulers() {
        startEntityScheduler();
        startItemCleanScheduler();
    }

    private void cancelTasks() {
        Arrays.asList(entityTaskId, itemCleanTaskId).forEach(id -> {
            if (id != -1) Bukkit.getScheduler().cancelTask(id);
        });
    }

    // ========== 实体限制系统 ==========
    private void startEntityScheduler() {
        entityTaskId = new BukkitRunnable() {
            int countdown = 30 * 60;

            @Override
            public void run() {
                handleCountdown(countdown,
                        5*60, 3*60, 1*60,
                        "§c实体限制检查倒计时:",
                        this::performEntityCleanup
                );
                countdown = (countdown > 0) ? countdown - 1 : 30 * 60;
            }

            private void performEntityCleanup() {
            }
        }.runTaskTimer(this, 0L, 20L).getTaskId();
    }

    private void performEntityCleanup() {
        int[] totalRemoved = {0};
        Bukkit.getWorlds().forEach(world -> {
            Arrays.stream(world.getLoadedChunks()).forEach(chunk -> {
                totalRemoved[0] += processChunk(chunk);
            });
        });
        broadcast("§a实体清理完成,共移除 " + totalRemoved[0] + " 个实体");
    }

    private int processChunk(Chunk chunk) {
        Map<EntityType, Integer> counter = new HashMap<>();
        List<Entity> toRemove = new ArrayList<>();

        Arrays.stream(chunk.getEntities()).forEach(entity -> {
            EntityType type = entity.getType();
            if (!entityLimits.containsKey(type)) return;

            int count = counter.getOrDefault(type, 0) + 1;
            counter.put(type, count);

            if (count > entityLimits.get(type)) {
                toRemove.add(entity);
            }
        });

        toRemove.forEach(Entity::remove);
        return toRemove.size();
    }

    // ========== 掉落物清理系统 ==========
    private void startItemCleanScheduler() {
        itemCleanTaskId = new BukkitRunnable() {
            int countdown = getConfig().getInt("item-clean.interval-minutes") * 60;

            @Override
            public void run() {
                handleCountdown(countdown,
                        getConfig().getInt("item-clean.warnings.5m") * 60,
                        getConfig().getInt("item-clean.warnings.3m") * 60,
                        getConfig().getInt("item-clean.warnings.1m") * 60,
                        "§6掉落物清理倒计时:",
                        () -> performItemCleanup(false)
                );
                countdown = (countdown > 0) ? countdown - 1 :
                        getConfig().getInt("item-clean.interval-minutes") * 60;
            }
        }.runTaskTimer(this, 0L, 20L).getTaskId();
    }

    private void performItemCleanup(boolean isManual) {
        Bukkit.getScheduler().runTask(this, () -> {
            int total = 0;

            // 遍历所有已加载区块
            for (World world : Bukkit.getWorlds()) {
                for (Chunk chunk : world.getLoadedChunks()) {
                    // 双重检查区块加载状态
                    if (!chunk.isLoaded()) continue;

                    // 遍历区块实体
                    for (Entity entity : chunk.getEntities()) {
                        if (entity instanceof Item) {
                            total++;
                        }
                    }
                }
            }

            // 执行清理命令
            Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "kill @e[type=item]");

            // 广播结果
            String message = isManual ?
                    "§a手动清理完成!共移除 " + total + " 个掉落物" :
                    "§a定时清理完成!共移除 " + total + " 个掉落物";
            broadcast(message);
        });
    }

    // ========== 通用工具方法 ==========
    private void handleCountdown(int current, int w5m, int w3m, int w1m,
                                 String prefix, Runnable callback) {
        if (current == w5m) broadcast(prefix + "5分钟");
        else if (current == w3m) broadcast(prefix + "3分钟");
        else if (current == w1m) broadcast(prefix + "1分钟");
        else if (current <= 10) {
            if (current > 0) {
                broadcast(prefix + current + "秒");
            } else {
                callback.run();
            }
        }
    }

    private void broadcast(String message) {
        Bukkit.getOnlinePlayers().forEach(p -> p.sendMessage(message));
        getLogger().info(ChatColor.stripColor(message));
    }

    // ========== 指令系统 ==========
    private void registerCommands() {
        register("clearloot", this::handleClearLoot);
        register("entitylimiter", this::handleMainCommand);
    }

    private void register(String cmd, CommandExecutor executor) {
        PluginCommand command = getCommand(cmd);
        if (command != null) {
            command.setExecutor(executor);
            command.setTabCompleter(this::onTabComplete);
        }
    }

    private boolean handleClearLoot(CommandSender sender, Command cmd,
                                    String label, String[] args) {
        if (!checkPermission(sender, "entitylimiter.clearloot")) return true;
        performItemCleanup(true);
        return true;
    }

    private boolean handleMainCommand(CommandSender sender, Command cmd,
                                      String label, String[] args) {
        if (!checkPermission(sender, "entitylimiter.admin")) return true;

        if (args.length == 0) {
            sendHelp(sender);
            return true;
        }

        switch (args[0].toLowerCase()) {
            case "reload":
                loadConfig();
                cancelTasks();
                startSchedulers();
                sender.sendMessage("§a配置已重载!");
                return true;
            case "runnow":
                performEntityCleanup();
                return true;
            default:
                sendHelp(sender);
                return true;
        }
    }

    public List<String> onTabComplete(CommandSender sender, Command cmd,
                                      String alias, String[] args) {
        List<String> list = new ArrayList<>();
        if (cmd.getName().equalsIgnoreCase("entitylimiter") && args.length == 1) {
            list.addAll(Arrays.asList("reload", "runnow"));
        }
        return list;
    }

    private boolean checkPermission(CommandSender sender, String perm) {
        if (!sender.hasPermission(perm)) {
            sender.sendMessage("§c权限不足!");
            return false;
        }
        return true;
    }

    private void sendHelp(CommandSender sender) {
        sender.sendMessage("§6===== EntityLimiter 帮助 =====");
        sender.sendMessage("§a/clearloot §7- 立即清理掉落物");
        sender.sendMessage("§a/entitylimiter reload §7- 重载配置");
        sender.sendMessage("§a/entitylimiter runnow §7- 立即清理实体");
    }
}
config.yml:

# 实体限制配置
entities:
ZOMBIE: 15
SKELETON: 10
CREEPER: 5

# 掉落物清理配置
item-clean:
interval-minutes: 30
warnings:
5m: 5
3m: 3
1m: 1
countdown-seconds: 10
check-loaded-chunks-only: true #仅检查已加载的块
plugin.yml:
name: EntityLimiter
main: MyPlugin.entityLimiter.EntityLimiter
version: 1.2.0
api-version: 1.21
authors: [YourName]
commands:
clearloot:
description: 清理全服掉落物
usage: /clearloot
permission: entitylimiter.clearloot
permission-message: "§c需要权限 entitylimiter.clearloot"

entitylimiter:
description: 插件管理命令
usage: /entitylimiter [reload|runnow]
permission: entitylimiter.admin
aliases: [el]
permission-message: "§c需要管理员权限"
作者
NaiveGod
价格
200金粒
下载
18
查看
800
首次发布
最后更新

评分

0.00 星 0 次评分

NaiveGod 的其他资源

最新更新

  1. 完善细节

    /clearlimit reload - 重载配置 /clearlimit runnow - 立即执行清理 统一了倒计时和消息优化
  2. 修正清理指令

    把kill改成minecraft:kill
后退
顶部 底部