CatAttrib

CatAttrib.java v2.3
支持自定义倍率、属性标签、提示语言配置,穿戴生效优化,可热重载
作者: ScriptIrc Engine

命令列表

  • SmileCat检测你当前装备/手持的全部猫属性
  • reloadattrib重载所有猫属性配置文件

权限列表

  • catattrib.chatdmg显示猫属性伤害和回血提示
package com.scriptirc.attribchecker;

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.CommandExecutor;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Entity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.*;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.entity.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.projectiles.ProjectileSource;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.regex.*;

/**
 * @pluginName CatAttrib
 * @author ScriptIrc Engine
 * @version 2.3
 * @description 支持自定义倍率、属性标签、提示语言配置,穿戴生效优化,可热重载
 * [command]SmileCat|检测你当前装备/手持的全部猫属性[/command]
 * [command]reloadattrib|重载所有猫属性配置文件[/command]
 * [Permission]catattrib.chatdmg|显示猫属性伤害和回血提示[/Permission]
 */
public class CatAttrib extends JavaPlugin implements CommandExecutor, Listener {

    private Map<String, List<String>> attrSynonyms = new HashMap<>();
    private File tagsConfigFile;
    private File mainConfigFile;
    private File langConfigFile;
    private Map<String, String> langMap = new HashMap<>();
    private Map<String, Double> rateMap = new HashMap<>();
    private static final Map<String, List<String>> DEFAULT_ATTRS = new LinkedHashMap<>();
    static {
        DEFAULT_ATTRS.put("生命值", Arrays.asList("生命值", "HP", "Health"));
        DEFAULT_ATTRS.put("防御", Arrays.asList("防御", "DEF", "防御力", "Defence"));
        DEFAULT_ATTRS.put("伤害", Arrays.asList("伤害", "攻击力", "DMG", "Damage"));
        DEFAULT_ATTRS.put("暴击", Arrays.asList("暴击", "暴击率", "Crit", "Cr"));
        DEFAULT_ATTRS.put("暴击伤害", Arrays.asList("暴击伤害", "暴伤", "CritDmg", "暴击倍数"));
        DEFAULT_ATTRS.put("移动速度", Arrays.asList("移动速度", "速度", "Speed", "MoveSpeed"));
        DEFAULT_ATTRS.put("攻击速度", Arrays.asList("攻击速度", "攻速", "AttackSpeed", "AS"));
        DEFAULT_ATTRS.put("吸血", Arrays.asList("吸血", "吸血率", "Lifesteal", "生命偷取", "ls"));
    }
    private static final Map<Material, Double> WEAPON_BASE_DAMAGE = new HashMap<>();
    static {
        WEAPON_BASE_DAMAGE.put(Material.WOODEN_SWORD, 4.0);
        WEAPON_BASE_DAMAGE.put(Material.STONE_SWORD, 5.0);
        WEAPON_BASE_DAMAGE.put(Material.IRON_SWORD, 6.0);
        WEAPON_BASE_DAMAGE.put(Material.GOLDEN_SWORD, 4.0);
        WEAPON_BASE_DAMAGE.put(Material.DIAMOND_SWORD, 7.0);
        WEAPON_BASE_DAMAGE.put(Material.NETHERITE_SWORD, 8.0);
        WEAPON_BASE_DAMAGE.put(Material.WOODEN_AXE, 7.0);
        WEAPON_BASE_DAMAGE.put(Material.STONE_AXE, 9.0);
        WEAPON_BASE_DAMAGE.put(Material.IRON_AXE, 9.0);
        WEAPON_BASE_DAMAGE.put(Material.GOLDEN_AXE, 7.0);
        WEAPON_BASE_DAMAGE.put(Material.DIAMOND_AXE, 9.0);
        WEAPON_BASE_DAMAGE.put(Material.NETHERITE_AXE, 10.0);
        WEAPON_BASE_DAMAGE.put(Material.BOW, 2.0);
        WEAPON_BASE_DAMAGE.put(Material.CROSSBOW, 2.0);
        WEAPON_BASE_DAMAGE.put(Material.TRIDENT, 8.0);
        WEAPON_BASE_DAMAGE.put(Material.AIR, 1.0);
    }
    private static final Map<Material, Double> WEAPON_BASE_ATTACK_SPEED = new HashMap<>();
    static {
        WEAPON_BASE_ATTACK_SPEED.put(Material.WOODEN_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.STONE_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.IRON_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.GOLDEN_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.DIAMOND_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.NETHERITE_SWORD, 1.6);
        WEAPON_BASE_ATTACK_SPEED.put(Material.WOODEN_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.STONE_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.IRON_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.GOLDEN_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.DIAMOND_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.NETHERITE_AXE, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.BOW, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.CROSSBOW, 1.0);
        WEAPON_BASE_ATTACK_SPEED.put(Material.TRIDENT, 1.1);
        WEAPON_BASE_ATTACK_SPEED.put(Material.AIR, 4.0);
    }

    private final Map<UUID, Map<String, Double>> playerAttrib = new HashMap<>();
    private final Random random = new Random();
    private final Map<UUID, Map<String, Double>> arrowAttribMap = new HashMap<>();
    private final Map<UUID, Material> arrowWeaponMap = new HashMap<>();
    private final Map<UUID, ItemStack> arrowWeaponStackMap = new HashMap<>();
    private static final Set<String> PASSIVE_KEYS = new HashSet<>(Arrays.asList("生命值","防御","移动速度"));
    private static final Set<String> ATTACK_KEYS = new HashSet<>(Arrays.asList("伤害","暴击","暴击伤害","吸血","攻击速度"));

    @Override
    public void onEnable() {
        Bukkit.getPluginManager().registerEvents(this, this);
        getCommand("SmileCat").setExecutor(this);
        try { getCommand("reloadattrib").setExecutor(this); } catch (Throwable ignore) {}
        initMainConfig();
        initAttributeTagsConfig();
        initLangConfig();
        for (Player player : Bukkit.getOnlinePlayers()) refreshPlayerAttrib(player);
        getLogger().info("【CatAttrib】已加载全部倍率、标签与语言配置,随时可定制!");
    }
    @Override
    public void onDisable() {
        for (Player player : Bukkit.getOnlinePlayers()) {
            resetPlayerHealthSpeed(player);
        }
        arrowAttribMap.clear();   playerAttrib.clear();
        arrowWeaponMap.clear();   arrowWeaponStackMap.clear();
    }

    private void initMainConfig() {
        mainConfigFile = new File(getDataFolder(), "catattrib_config.yml");
        if (!getDataFolder().exists()) getDataFolder().mkdirs();
        boolean writeDefault = false;
        if (!mainConfigFile.exists()) writeDefault = true;
        YamlConfiguration yml = YamlConfiguration.loadConfiguration(mainConfigFile);
        // 默认倍率配置
        if (writeDefault) {
            yml.set("critical_base", 1.0); // 暴击基础倍率
            yml.set("critical_per10", 0.5); // 每10点暴击伤害倍率加成
            yml.set("lifesteal_rate", 1.0); // 吸血伤害百分比
            yml.set("damage_bonus_rate", 1.0); // lore伤害加成倍率
            yml.set("move_speed_base", 0.2); // 基础移速
            yml.set("move_speed_per", 0.01); // lore移动速度每点加成
            yml.set("attack_speed_base", 1.0); // 基础攻速
            try { yml.save(mainConfigFile); } catch (IOException ignore) {}
        }
        rateMap.clear();
        for(String k:yml.getKeys(false)){
            rateMap.put(k, yml.getDouble(k));
        }
    }

    private void initAttributeTagsConfig() {
        tagsConfigFile = new File(getDataFolder(), "attribute_tags.yml");
        boolean writeDefault = false;
        if (!tagsConfigFile.exists()) writeDefault = true;
        YamlConfiguration yml = YamlConfiguration.loadConfiguration(tagsConfigFile);
        if (writeDefault) {
            for (Map.Entry<String, List<String>> entry : DEFAULT_ATTRS.entrySet()) {
                yml.set(entry.getKey(), entry.getValue());
            }
            try { yml.save(tagsConfigFile); } catch (IOException ignore) {}
        }
        attrSynonyms.clear();
        for (String key : DEFAULT_ATTRS.keySet()) {
            List<String> valset = yml.getStringList(key);
            if(valset==null||valset.isEmpty()) valset = DEFAULT_ATTRS.get(key);
            attrSynonyms.put(key, new ArrayList<>(valset));
        }
    }

    private void initLangConfig() {
        langConfigFile = new File(getDataFolder(), "catattrib_lang.yml");
        boolean writeDefault = false;
        if (!langConfigFile.exists()) writeDefault = true;
        YamlConfiguration yml = YamlConfiguration.loadConfiguration(langConfigFile);
        if (writeDefault) {
            yml.set("actionbar_damage", "§e你对 §c{target} §e造成 §a{damage} §e点喵击伤害");
            yml.set("actionbar_heal", "§d[猫吸血] §a你吸收 §c+{heal} §a生命");
            yml.set("actionbar_behit", "§c你受到 §e{source} §c的 §c{damage} §c点喵击伤害");
            yml.set("crit_message", "§b[猫暴击] 最终伤害 {finaldmg} (基础{base} 加成{add} 药水{pot} 暴击倍数{critmult} 附魔{ench})");
            yml.set("lifesteal_chat", "[猫吸血] 你通过吸血回复了 +{heal} 生命");
            yml.set("damage_chat", "[猫击] 你对 {target} 造成 {damage} 点伤害");
            yml.set("behit_chat", "[猫击] 你受到 {source} 的 {damage} 点伤害");
            yml.set("reload_success", "§a[CatAttrib] 属性配置文件重载成功。");
            yml.set("cat_check_title", "§a[猫属性检测](只展示装备栏属性):");
            try { yml.save(langConfigFile); } catch(IOException ignore) {}
        }
        langMap.clear();
        for(String key : yml.getKeys(false)){
            langMap.put(key, yml.getString(key));
        }
    }

    private String formatLang(String key, Map<String,String> params){
        String txt = langMap.getOrDefault(key,"");
        if(params==null) return txt;
        for(Map.Entry<String,String> e:params.entrySet()){
            txt = txt.replace("{"+e.getKey()+"}", e.getValue());
        }
        return txt;
    }

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if (label.equalsIgnoreCase("reloadattrib")) {
            initMainConfig();
            initAttributeTagsConfig();
            initLangConfig();
            sender.sendMessage(langMap.getOrDefault("reload_success","[CatAttrib] 配置文件重载成功!"));
            sender.sendMessage("§e倍率配置: "+rateMap);
            sender.sendMessage("§e属性别名: "+attrSynonyms);
            return true;
        }
        if (label.equalsIgnoreCase("SmileCat")) {
            if (!(sender instanceof Player)) {
                sender.sendMessage("喵~ 只有玩家可以检测自己的猫属性哦!");
                return true;
            }
            Player p = (Player)sender;
            Map<String, Double> attrs = playerAttrib.getOrDefault(p.getUniqueId(), Collections.emptyMap());
            p.sendMessage(langMap.getOrDefault("cat_check_title","§a[猫属性检测]:"));
            for (String k : attrSynonyms.keySet()) {
                double v = attrs.getOrDefault(k,0d);
                p.sendMessage(String.format("§e%s§f: §b%s",k,formatNum(v)));
            }
            return true;
        }
        return false;
    }

    @EventHandler public void onJoin(PlayerJoinEvent e){ refreshPlayerAttrib(e.getPlayer()); }
    @EventHandler public void onQuit(PlayerQuitEvent e){ resetPlayerHealthSpeed(e.getPlayer()); playerAttrib.remove(e.getPlayer().getUniqueId()); }
    @EventHandler public void onItemHeld(PlayerItemHeldEvent e){ Bukkit.getScheduler().runTaskLater(this, () -> refreshPlayerAttrib(e.getPlayer()), 1L); }
    @EventHandler public void onSwapHand(PlayerSwapHandItemsEvent e){ Bukkit.getScheduler().runTaskLater(this, () -> refreshPlayerAttrib(e.getPlayer()), 1L); }
    @EventHandler public void onInventoryClick(InventoryClickEvent e){
        if (e.getWhoClicked() instanceof Player) {
            Bukkit.getScheduler().runTaskLater(this, () -> refreshPlayerAttrib((Player) e.getWhoClicked()), 1L);
        }
    }

    private void refreshPlayerAttrib(Player p){
        Map<String, Double> total = new HashMap<>();
        Arrays.asList(p.getInventory().getArmorContents()).forEach(item -> {
            Map<String, Double> it = attribFromItem(item);
            for(Map.Entry<String,Double> e:it.entrySet()){
                if(PASSIVE_KEYS.contains(e.getKey())){
                    total.put(e.getKey(), total.getOrDefault(e.getKey(), 0d) + e.getValue());
                }
            }
        });
        playerAttrib.put(p.getUniqueId(), total);
        double hp = total.getOrDefault("生命值", 0d);
        setPlayerMaxHealth(p, 20d + hp);
        if(p.getHealth() > p.getMaxHealth()) p.setHealth(p.getMaxHealth());
        double movePercent = Math.max(0d, Math.min(100d, total.getOrDefault("移动速度", 0d)));
        double moveBase = rateMap.getOrDefault("move_speed_base", 0.2);
        double movePer = rateMap.getOrDefault("move_speed_per", 0.01);
        double speed = moveBase + movePer * movePercent;
        if (speed > 1.0) speed = 1.0;
        if (speed < 0.01) speed = 0.01;
        try { p.setWalkSpeed((float) speed); } catch (Throwable ignore) {}
    }

    private void mergeAttribSelective(Map<String,Double> main, Map<String,Double> add, Set<String> allow){
        for(Map.Entry<String,Double> e:add.entrySet()){
            if(allow.contains(e.getKey())){
                main.put(e.getKey(), main.getOrDefault(e.getKey(), 0d)+e.getValue());
            }
        }
    }

    private Map<String, Double> attribFromItem(ItemStack item) {
        Map<String, Double> at = new HashMap<>();
        if (item==null || !item.hasItemMeta() || !item.getItemMeta().hasLore()) return at;
        ItemMeta meta = item.getItemMeta();
        List<String> lore = meta.getLore();
        Pattern pattern = Pattern.compile("([一-龥A-Za-z]+)[::]\\s*([-]?\\d+\\.?\\d*)");
        for (String line : lore) {
            String plain = line.replaceAll("§[0-9a-fk-orA-FK-OR]", "");
            Matcher m = pattern.matcher(plain);
            while (m.find()) {
                String key = m.group(1); String vstr = m.group(2);
                for (Map.Entry<String, List<String>> syn : attrSynonyms.entrySet()) {
                    if (syn.getValue().stream().anyMatch(alias -> alias.equalsIgnoreCase(key))) {
                        try {
                            double val = Double.parseDouble(vstr);
                            at.put(syn.getKey(), at.getOrDefault(syn.getKey(), 0d)+val);
                        } catch (Exception ignored) {}
                        break;
                    }
                }
            }
        }
        return at;
    }

    @EventHandler
    public void onDamage(EntityDamageByEntityEvent e) {
        if (!(e.getEntity() instanceof LivingEntity)) return;
        LivingEntity victim = (LivingEntity) e.getEntity();
        Player attacker = null;
        Map<String, Double> passiveAtr = null;
        Map<String, Double> weaponAtr = null;
        Material weaponMat = null;
        ItemStack weaponItem = null;
        if (e.getDamager() instanceof Player) {
            attacker = (Player) e.getDamager();
            passiveAtr = playerAttrib.getOrDefault(attacker.getUniqueId(), Collections.emptyMap());
            weaponItem = attacker.getInventory().getItemInMainHand();
            weaponMat = (weaponItem==null?Material.AIR:weaponItem.getType());
            weaponAtr = attribFromItem(weaponItem);
        } else if (e.getDamager() instanceof Projectile) {
            Projectile proj = (Projectile) e.getDamager();
            ProjectileSource shooter = proj.getShooter();
            if(shooter instanceof Player) {
                attacker = (Player) shooter;
                Map<String, Double> attr = arrowAttribMap.get(proj.getUniqueId());
                weaponAtr = attr!=null? attr : new HashMap<>();
                passiveAtr = playerAttrib.getOrDefault(attacker.getUniqueId(), Collections.emptyMap());
                weaponMat = arrowWeaponMap.getOrDefault(proj.getUniqueId(), Material.BOW);
                weaponItem = arrowWeaponStackMap.get(proj.getUniqueId());
            }
        }
        if (attacker != null) {
            double base = getBaseWeaponDamage(weaponMat, weaponItem);
            double origEventDamage = e.getDamage();
            Map<String,Double> atkAtr = new HashMap<>();
            if(weaponAtr!=null) mergeAttribSelective(atkAtr, weaponAtr, ATTACK_KEYS);
            double loreAdd = atkAtr.getOrDefault("伤害", 0d) * rateMap.getOrDefault("damage_bonus_rate", 1.0);
            double attackSpeed = WEAPON_BASE_ATTACK_SPEED.getOrDefault(weaponMat, 4.0) +
                    atkAtr.getOrDefault("攻击速度", 0d) * rateMap.getOrDefault("attack_speed_base", 1.0);
            double critProb = atkAtr.getOrDefault("暴击",0d);
            double critDmg = atkAtr.getOrDefault("暴击伤害",0d);
            boolean isCrit = (critProb>0 && random.nextDouble() < critProb);
            double enchBonus = origEventDamage - base;
            if(enchBonus<0) enchBonus = 0;
            double totalDamage = origEventDamage + loreAdd;
            if(isCrit) {
                // 动态倍率配比
                double realCritDmg = rateMap.getOrDefault("critical_base", 1.0) +
                        critDmg / 10.0 * rateMap.getOrDefault("critical_per10", 0.5);
                double norm = base + loreAdd + (origEventDamage-base - enchBonus);
                double afterCrit = norm * realCritDmg + enchBonus;
                totalDamage = afterCrit;
                if(attacker.hasPermission("catattrib.chatdmg") || attacker.isOp()){
                    Map<String,String> m = new HashMap<>();
                    m.put("finaldmg",formatNum(afterCrit)); m.put("base",formatNum(base)); m.put("add",formatNum(loreAdd));
                    m.put("pot",formatNum(origEventDamage-base-enchBonus));
                    m.put("critmult",formatNum(realCritDmg)); m.put("ench",formatNum(enchBonus));
                    attacker.sendMessage(formatLang("crit_message", m));
                }
            }
            double victimDef = 1.0;
            if(victim instanceof Player){
                Map<String, Double> victimPassive = playerAttrib.getOrDefault(victim.getUniqueId(), Collections.emptyMap());
                victimDef = Math.max(1.0, victimPassive.getOrDefault("防御", 0d));
            }
            totalDamage = totalDamage / victimDef;
            e.setDamage(Math.max(0.1, totalDamage));
            double lifesteal = atkAtr.getOrDefault("吸血", 0d) * rateMap.getOrDefault("lifesteal_rate",1.0);
            if(lifesteal > 0.0 && attacker != null && totalDamage > 0.0){
                double heal = totalDamage * (lifesteal/100.0);
                double originHP = attacker.getHealth();
                double maxHP = attacker.getMaxHealth();
                double finalHP = Math.min(originHP + heal, maxHP);
                try{ attacker.setHealth(finalHP); } catch(Exception ignored){}
                Map<String,String> m = new HashMap<>();
                m.put("heal", formatNum(heal));
                sendActionBar(attacker, formatLang("actionbar_heal", m));
                if(attacker.hasPermission("catattrib.chatdmg") || attacker.isOp())
                    attacker.sendMessage(formatLang("lifesteal_chat", m));
            }
        }
        if (victim instanceof Player && attacker == null) {
            Player v = (Player)victim;
            Map<String, Double> atr = playerAttrib.getOrDefault(v.getUniqueId(), Collections.emptyMap());
            double def = Math.max(1.0, atr.getOrDefault("防御",0d));
            double dmg = e.getDamage() / def;
            e.setDamage(Math.max(0.1, dmg));
        }
        try {
            double finalDmg = e.getFinalDamage();
            if (attacker != null) {
                String tarName = getEntityShowName(victim);
                Map<String, String> m = new HashMap<>();
                m.put("target",tarName); m.put("damage",formatNum(finalDmg));
                sendActionBar(attacker, formatLang("actionbar_damage", m));
                if(attacker.hasPermission("catattrib.chatdmg") || attacker.isOp())
                    attacker.sendMessage(formatLang("damage_chat", m));
            }
            if (victim instanceof Player) {
                String srcName = attacker==null ? getEntityShowName(e.getDamager()) : getEntityShowName(attacker);
                Map<String,String> m = new HashMap<>();
                m.put("source",srcName); m.put("damage",formatNum(finalDmg));
                sendActionBar((Player)victim, formatLang("actionbar_behit", m));
                Player v = (Player)victim;
                if(v.hasPermission("catattrib.chatdmg") || v.isOp())
                    v.sendMessage(formatLang("behit_chat", m));
            }
        } catch (Exception ex) {
            getLogger().warning("伤害ActionBar/聊天栏发送异常: "+ex.getMessage());
        }
    }

    @EventHandler
    public void onEntityDamage(EntityDamageEvent e){
        try {
            if(e instanceof EntityDamageByEntityEvent) return;
            if(e.getEntity() instanceof Player){
                String cause = e.getCause().name();
                Map<String,String> m = new HashMap<>();
                m.put("source",cause); m.put("damage",formatNum(e.getFinalDamage()));
                sendActionBar((Player)e.getEntity(), formatLang("actionbar_behit", m));
                Player v = (Player)e.getEntity();
                if(v.hasPermission("catattrib.chatdmg") || v.isOp())
                    v.sendMessage(formatLang("behit_chat", m));
            }
        } catch(Exception ex){
            getLogger().warning("通用伤害ActionBar/聊天栏发送异常:"+ex.getMessage());
        }
    }

    @EventHandler
    public void onProjectileLaunch(ProjectileLaunchEvent event) {
        if (!(event.getEntity().getShooter() instanceof Player)) return;
        Player shooter = (Player) event.getEntity().getShooter();
        Map<String, Double> attr = attribFromItem(shooter.getInventory().getItemInMainHand());
        arrowAttribMap.put(event.getEntity().getUniqueId(), attr);
        ItemStack main = shooter.getInventory().getItemInMainHand();
        arrowWeaponMap.put(event.getEntity().getUniqueId(), (main==null?Material.BOW:main.getType()));
        if(main!=null && main.getType()!=Material.AIR && main.getAmount()>0){
            arrowWeaponStackMap.put(event.getEntity().getUniqueId(), main.clone());
        }else{
            arrowWeaponStackMap.put(event.getEntity().getUniqueId(), null);
        }
    }
    @EventHandler
    public void onDamageAfter(EntityDamageEvent event){
        if(event.getEntity() instanceof LivingEntity){
            arrowAttribMap.entrySet().removeIf(entry -> Bukkit.getEntity(entry.getKey())==null);
            arrowWeaponMap.entrySet().removeIf(entry -> Bukkit.getEntity(entry.getKey())==null);
            arrowWeaponStackMap.entrySet().removeIf(entry -> Bukkit.getEntity(entry.getKey())==null);
        }
    }
    private double getBaseWeaponDamage(Material mat, ItemStack item) {
        if (item == null || item.getType() == Material.AIR || item.getAmount() <= 0) return 1.0;
        return WEAPON_BASE_DAMAGE.getOrDefault(mat, 1.0);
    }
    private void setPlayerMaxHealth(Player p, double hp) {
        try { p.setMaxHealth(hp); } catch (Throwable ignore2) {}
    }
    private void resetPlayerHealthSpeed(Player p) {
        setPlayerMaxHealth(p, 20d);
        if(p.getHealth() > 20d) p.setHealth(20d);
        try{ p.setWalkSpeed(0.2f); } catch (Throwable ignore) {}
    }
    private String formatNum(double d) {
        return String.format("%.1f", d);
    }
    private String getEntityShowName(Entity e) {
        if (e==null) return "未知";
        try {
            String cn = e.getCustomName();
            if (cn != null && !cn.isEmpty()) {
                return stripColor(cn);
            }
        } catch (Throwable ignore) {}
        if (e instanceof Player) {
            return ((Player)e).getName();
        }
        return e.getType().name();
    }
    private String stripColor(String s) {
        if(s==null) return "";
        return s.replaceAll("§[0-9a-fk-orA-FK-OR]", "");
    }
    private void sendActionBar(Player p, String msg){
        try { p.sendActionBar(msg); } catch (Throwable ignore) {
            try { p.spigot().sendMessage(net.md_5.bungee.api.ChatMessageType.ACTION_BAR,
                    new net.md_5.bungee.api.chat.TextComponent(msg));
            } catch (Throwable err) { p.sendMessage(msg); }
        }
    }
}
上一篇: BackHome下一篇: AuthSystemTutorial

举报内容

意见反馈