EntityLimiter —— 掉落物自动清理和实体区块数量限制 icon

EntityLimiter —— 掉落物自动清理和实体区块数量限制 -----

自动掉落物清理和区块实体限制



这是我用DeepSeek写出来的插件
功能一:自定义分钟清理一次全局掉落物,清理前有倒计时提示。
功能二:自定义限制单个区块内实体数量,超出的清除
指令:
手动掉落物清理:/clearloot
手动实体清理:/entitylimiter runnow
重载配置:/entitylimiter reload
Code (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需要管理员权限"
Resource Information
Author:
----------
Total Downloads: 29
First Release: Feb 10, 2025
Last Update: Feb 11, 2025
Category: ---------------
All-Time Rating:
0 ratings
Version -----
Released: --------------------
Downloads: ------
Version Rating:
----------------------
-- ratings