CatAttrib.java v2.5
支持自定义倍率、属性标签、提示语言配置,穿戴生效优化、手持检测,仅显示手持属性,兼容大小写及多种冒号、分隔符
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.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.event.Listener;
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.5
* @description 支持自定义倍率、属性标签、提示语言配置,穿戴生效优化、手持检测,仅显示手持属性,兼容大小写及多种冒号、分隔符
* [command]SmileCat|检测你手持物品的全部猫属性数值
* [command]reloadattrib|重载所有猫属性配置文件
* [Permission]catattrib.chatdmg|显示猫属性伤害和回血提示
*/
public class CatAttrib extends JavaPlugin implements CommandExecutor, Listener {
private Map<String, List<String>> attrSynonyms = new HashMap<>();
private File tagsConfigFile, mainConfigFile, 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"));
}
@Override
public void onEnable() {
getCommand("SmileCat").setExecutor(this);
getCommand("reloadattrib").setExecutor(this);
initMainConfig();
initAttributeTagsConfig();
initLangConfig();
getLogger().info("【CatAttrib】配置加载完毕,已启用。");
}
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);
yml.set("lifesteal_rate", 1.0);
yml.set("damage_bonus_rate", 1.0);
yml.set("move_speed_base", 0.2);
yml.set("move_speed_per", 0.01);
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("cat_check_title", "§a[猫属性检测 - 手持物品]:");
yml.set("no_attrib", "§7你未手持具有属性的物品。");
yml.set("reload_success", "§a[CatAttrib] 属性配置文件重载成功。");
try { yml.save(langConfigFile); } catch(IOException ignore) {}
}
langMap.clear();
for(String key : yml.getKeys(false)){
langMap.put(key, yml.getString(key));
}
}
@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;
ItemStack main = p.getInventory().getItemInMainHand();
Map<String, Double> attrs = attribFromItem(main);
p.sendMessage(langMap.getOrDefault("cat_check_title", "§a[猫属性检测 - 手持物品]:"));
if(main == null || main.getType()==Material.AIR || attrs.isEmpty()){
p.sendMessage(langMap.getOrDefault("no_attrib", "§7你未手持具有属性的物品。"));
return true;
}
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;
}
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();
// 兼容全半角、所有类型“冒号”与空格分隔符,允许如“生命值:10”或“HP : 20”
Pattern pattern = Pattern.compile("([\\u4e00-\\u9fa5A-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;
}
private String formatNum(double d) {
return String.format("%.1f", d);
}
}