添加套装效果触发

This commit is contained in:
yhy
2026-07-12 08:16:37 +08:00
parent 67461082a5
commit 8c60c9daaf
15 changed files with 369 additions and 13 deletions

View File

@@ -38,6 +38,12 @@
<version>26.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.lumine.mythic.bukkit</groupId>
<artifactId>MythicMobs</artifactId>
<version>5.12.0-SNAPSHOT-548b7d33</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -3,6 +3,7 @@ package com.io.yaohun.myitems;
import com.io.yaohun.myitems.api.AttributeData;
import com.io.yaohun.myitems.api.AttributeType;
import com.io.yaohun.myitems.api.EntityAttributeAPI;
import com.io.yaohun.myitems.api.SuitLoreAPI;
import com.io.yaohun.myitems.builder.ItemTemplateBuilder;
import com.io.yaohun.myitems.commands.AttCommand;
import com.io.yaohun.myitems.commands.MyItemCommand;
@@ -33,6 +34,7 @@ import java.util.List;
public class MyItems extends JavaPlugin {
public static boolean debug;
private static MyItems instance;
private CacheManager cacheManager;
private DamageEngine damageEngine;
@@ -58,6 +60,7 @@ public class MyItems extends JavaPlugin {
getServer().getPluginManager().registerEvents(new ToolDurabilityListener(attributeManager), this);
getServer().getPluginManager().registerEvents(new SuitListener(suitManager, attributeManager), this);
getServer().getPluginManager().registerEvents(new EntityCleanupListener(entityAttributeStorage), this);
getServer().getPluginManager().registerEvents(new MythicMobsAttributeListener(), this);
getCommand("att").setExecutor(new AttCommand());
getCommand("repair").setExecutor(new RepairCommand());
@@ -69,6 +72,7 @@ public class MyItems extends JavaPlugin {
ItemManager.reloadItemManager(MyItems.inst());
suitManager.reloadSuitManager(MyItems.inst());
for (Player player : Bukkit.getOnlinePlayers()){
SuitLoreAPI.refreshEquipmentLore(player);
suitManager.refreshPlayerSuitState(player, false);
attributeManager.refresh(player);
}

View File

@@ -2,7 +2,6 @@ package com.io.yaohun.myitems.api;
import com.io.yaohun.myitems.MyItems;
import com.io.yaohun.myitems.manage.EntityAttributeStorage;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
@@ -73,6 +72,10 @@ public final class EntityAttributeAPI {
.getAttribute(livingEntity.getUniqueId(), type);
}
public static boolean isSupportedAttribute(String key) {
return matchType(key) != null;
}
private static AttributeType matchType(String key) {
if (key == null) {
return null;

View File

@@ -0,0 +1,207 @@
package com.io.yaohun.myitems.api;
import com.io.yaohun.myitems.MyItems;
import com.io.yaohun.myitems.manage.SuitManager;
import com.io.yaohun.myitems.util.ItemAttributeEditor;
import com.io.yaohun.myitems.util.ItemAttributeUtil;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class SuitLoreAPI {
private static final Pattern SUIT_PROGRESS_PATTERN = Pattern.compile("\\(\\s*(?:\\{suit}|\\d+)\\s*/\\s*\\d+\\s*\\)");
private static final Pattern SUIT_REQUIRE_PATTERN = Pattern.compile("/\\s*(\\d+)");
private SuitLoreAPI() {
}
public static boolean refresh(Player player) {
if (player == null || MyItems.inst() == null) {
return false;
}
boolean loreChanged = refreshEquipmentLore(player);
boolean suitChanged = MyItems.inst().getSuitManager().refreshPlayerSuitState(player, true);
if (loreChanged || suitChanged) {
MyItems.inst().getAttributeManager().markDirty(player);
MyItems.inst().getAttributeManager().refresh(player);
}
return loreChanged || suitChanged;
}
public static boolean refreshEquipmentLore(Player player) {
return refreshInventoryLore(player);
}
public static boolean refreshInventoryLore(Player player) {
if (player == null || player.getInventory() == null) {
return false;
}
boolean changed = false;
for (ItemStack item : player.getInventory().getContents()) {
changed |= refreshItem(player, item);
}
for (ItemStack item : player.getInventory().getArmorContents()) {
changed |= refreshItem(player, item);
}
changed |= refreshItem(player, player.getInventory().getItemInMainHand());
changed |= refreshItem(player, player.getInventory().getItemInOffHand());
changed |= refreshItem(player, player.getInventory().getHelmet());
changed |= refreshItem(player, player.getInventory().getChestplate());
changed |= refreshItem(player, player.getInventory().getLeggings());
changed |= refreshItem(player, player.getInventory().getBoots());
return changed;
}
public static boolean refreshItem(Player player, ItemStack item) {
if (player == null || item == null || item.getType() == Material.AIR || !item.hasItemMeta()) {
return false;
}
String suitId = ItemAttributeUtil.readSuitId(item);
if (isDefaultSuitId(suitId)) {
return false;
}
ItemMeta meta = item.getItemMeta();
if (meta == null || !meta.hasLore()) {
return false;
}
List<String> lore = meta.getLore();
if (lore == null || lore.isEmpty()) {
return false;
}
String template = ItemAttributeUtil.readSuitLoreTemplate(item);
String anchor = ItemAttributeUtil.readSuitLoreAnchor(item);
int lineIndex = findSuitLoreLine(lore, anchor);
if (lineIndex < 0) {
return false;
}
if (template == null || template.isEmpty()) {
String line = lore.get(lineIndex);
if (line.contains("{suit}")) {
bindSuitLoreTemplate(item, line);
template = line;
anchor = buildAnchor(line);
}
}
SuitManager suitManager = MyItems.inst().getSuitManager();
int require = suitManager.getSuitRequire(suitId);
if (require <= 0) {
require = parseRequire(template, lore.get(lineIndex));
}
if (require <= 0) {
return false;
}
int count = Math.min(suitManager.getSuitCount(player, suitId), require);
String newLine = buildSuitLoreLine(template, lore.get(lineIndex), count, require);
if (newLine == null || newLine.equals(lore.get(lineIndex))) {
return false;
}
lore.set(lineIndex, newLine);
meta.setLore(lore);
item.setItemMeta(meta);
if ((anchor == null || anchor.isEmpty()) && template != null && !template.isEmpty()) {
ItemAttributeEditor.setSuitLoreAnchor(item, buildAnchor(template));
}
return true;
}
public static void bindSuitLoreTemplate(ItemStack item, String templateLine) {
if (item == null || templateLine == null || templateLine.isEmpty()) {
return;
}
ItemAttributeEditor.setSuitLoreTemplate(item, templateLine);
ItemAttributeEditor.setSuitLoreAnchor(item, buildAnchor(templateLine));
}
public static boolean isDefaultSuitId(String suitId) {
return suitId == null || suitId.isEmpty() || "default".equalsIgnoreCase(suitId);
}
private static int findSuitLoreLine(List<String> lore, String anchor) {
for (int i = lore.size() - 1; i >= 0; i--) {
String line = lore.get(i);
String plain = stripColor(line);
if (line.contains("{suit}")) {
return i;
}
if (anchor != null && !anchor.isEmpty() && plain.contains(anchor)) {
return i;
}
if (plain.contains("套装") && SUIT_PROGRESS_PATTERN.matcher(plain).find()) {
return i;
}
}
return -1;
}
private static String buildSuitLoreLine(String template, String currentLine, int count, int require) {
if (template != null && !template.isEmpty()) {
String line = template.replace("{suit}", String.valueOf(count));
Matcher matcher = SUIT_PROGRESS_PATTERN.matcher(line);
if (matcher.find()) {
return matcher.replaceFirst("(" + count + "/" + require + ")");
}
return line;
}
Matcher matcher = SUIT_PROGRESS_PATTERN.matcher(currentLine);
if (matcher.find()) {
return matcher.replaceFirst("(" + count + "/" + require + ")");
}
return null;
}
private static int parseRequire(String template, String currentLine) {
int require = parseRequireFromLine(template);
if (require > 0) {
return require;
}
return parseRequireFromLine(currentLine);
}
private static int parseRequireFromLine(String line) {
if (line == null || line.isEmpty()) {
return 0;
}
Matcher matcher = SUIT_REQUIRE_PATTERN.matcher(stripColor(line));
if (!matcher.find()) {
return 0;
}
try {
return Integer.parseInt(matcher.group(1));
} catch (NumberFormatException e) {
return 0;
}
}
private static String buildAnchor(String templateLine) {
String plain = stripColor(templateLine);
plain = SUIT_PROGRESS_PATTERN.matcher(plain).replaceAll("");
return plain.trim();
}
private static String stripColor(String line) {
String stripped = ChatColor.stripColor(line == null ? "" : line);
return stripped == null ? "" : stripped;
}
}

View File

@@ -1,6 +1,7 @@
package com.io.yaohun.myitems.builder;
import com.io.yaohun.myitems.api.AttributeType;
import com.io.yaohun.myitems.api.SuitLoreAPI;
import com.io.yaohun.myitems.api.TierType;
import com.io.yaohun.myitems.data.ItemTemplate;
import com.io.yaohun.myitems.manage.ItemManager;
@@ -37,6 +38,7 @@ public class ItemTemplateBuilder {
meta.setDisplayName(DemonAPI.convertHexColor(itemName));
int gemLine = 0;
String suitLoreTemplate = null;
List<String> lore = new ArrayList<>();
if(!template.getLore().isEmpty()){
List<String> lores = new ArrayList<>(template.getLore());
@@ -45,6 +47,10 @@ public class ItemTemplateBuilder {
line = line.replace("{tier_name}", tierType.getDisplayName());
line = line.replace("{tier_character}", tierType.getCharacter());
line = line.replace("{item_icon}", template.getItemIcon());
if(!SuitLoreAPI.isDefaultSuitId(template.getSuitId()) && line.contains("{suit}")) {
suitLoreTemplate = line;
line = line.replace("{suit}", "0");
}
if(line.contains("{GemSlot}")) {
line = line.replace("{GemSlot}", EMPTY_LINE_LORE);
gemLine = i;
@@ -65,6 +71,9 @@ public class ItemTemplateBuilder {
}
ItemAttributeEditor.setTemplateId(itemStack, template.getItemId());
ItemAttributeEditor.setSuitId(itemStack, template.getSuitId());
if (suitLoreTemplate != null) {
SuitLoreAPI.bindSuitLoreTemplate(itemStack, suitLoreTemplate);
}
Map<AttributeType, ItemTemplate.AttributeRandomValue> attributes = template.getAttributes(tierType);
if(!attributes.isEmpty()) {

View File

@@ -5,6 +5,7 @@ import com.io.yaohun.myitems.api.AttributeData;
import com.io.yaohun.myitems.api.AttributeType;
import com.io.yaohun.myitems.api.EntityAttributeAPI;
import com.io.yaohun.myitems.api.EquipmentSlotType;
import com.io.yaohun.myitems.api.SuitLoreAPI;
import com.io.yaohun.myitems.builder.ItemTemplateBuilder;
import com.io.yaohun.myitems.config.Config;
import com.io.yaohun.myitems.gui.PanelGui;
@@ -51,12 +52,22 @@ public class MyItemCommand implements CommandExecutor, TabCompleter {
if(!sender.hasPermission("admin.use")){
return true;
}
if (args.length == 1 && "debug".equalsIgnoreCase(args[0])) {
if(!MyItems.debug){
MyItems.debug = true;
} else {
MyItems.debug = false;
}
sender.sendMessage("§f[§6属性§f] §a已切换为: " + (MyItems.debug ? "§c调试模式" : "§a正常模式"));
return true;
}
if(args.length == 1 && "reload".equalsIgnoreCase(args[0])){
Config.reloadConfig(MyItems.inst());
MessageUtil.init(MyItems.inst());
ItemManager.reloadItemManager(MyItems.inst());
MyItems.inst().getSuitManager().reloadSuitManager(MyItems.inst());
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
SuitLoreAPI.refreshEquipmentLore(onlinePlayer);
MyItems.inst().getSuitManager().refreshPlayerSuitState(onlinePlayer, false);
MyItems.inst().getAttributeManager().markDirty(onlinePlayer);
MyItems.inst().getAttributeManager().refresh(onlinePlayer);
@@ -169,6 +180,7 @@ public class MyItemCommand implements CommandExecutor, TabCompleter {
player.sendMessage("§2/" + label + " durability §e[now] §b<max> §f- §2设置耐久");
player.sendMessage("§2/" + label + " slot §e[value] §f- §2设置槽位类型");
player.sendMessage("§2/" + label + " clear §f- §2清理物品属性");
player.sendMessage("§2/" + label + " debug §f- §c开启调试输出");
player.sendMessage("§e==----- ======= §2属性编辑 §e======= -----==");
player.sendMessage("§r");
}

View File

@@ -1,6 +1,7 @@
package com.io.yaohun.myitems.commands;
import com.io.yaohun.myitems.MyItems;
import com.io.yaohun.myitems.api.SuitLoreAPI;
import com.io.yaohun.myitems.util.MessageUtil;
import com.io.yaohun.myitems.util.RepairUtil;
import org.bukkit.Bukkit;
@@ -84,6 +85,7 @@ public class RepairCommand implements CommandExecutor, TabCompleter {
}
private void refreshTarget(Player target) {
SuitLoreAPI.refreshEquipmentLore(target);
MyItems.inst().getSuitManager().refreshPlayerSuitState(target, true);
MyItems.inst().getAttributeManager().markDirty(target);
MyItems.inst().getAttributeManager().refresh(target);

View File

@@ -12,7 +12,7 @@ import java.util.concurrent.ThreadLocalRandom;
public class DamageEngine {
private static final double PVE_DEFENSE_CONSTANT = 1000.0;
private static final double PVE_DEFENSE_CONSTANT = 100.0;
private static final double PVP_DEFENSE_CONSTANT = 1000.0;
private static final double BLOCK_DAMAGE_RATE = 0.5D;
private static final double BLOCK_REFLECT_RATE = 0.1D;

View File

@@ -0,0 +1,77 @@
package com.io.yaohun.myitems.listener;
import com.io.yaohun.myitems.MyItems;
import com.io.yaohun.myitems.api.EntityAttributeAPI;
import io.lumine.mythic.api.config.MythicConfig;
import io.lumine.mythic.api.mobs.MythicMob;
import io.lumine.mythic.bukkit.events.MythicMobSpawnEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MythicMobsAttributeListener implements Listener {
private static final String ATTRIBUTE_SECTION = "Attribute";
private static final String ATTRIBUTE_SOURCE = "mythicmob_spawner";
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onMythicMobSpawn(MythicMobSpawnEvent event) {
LivingEntity entity = event.getLivingEntity();
MythicMob mythicMob = event.getMobType();
if (entity == null || mythicMob == null) {
return;
}
Map<String, Double> attributes = readAttributes(mythicMob);
if (attributes.isEmpty()) {
return;
}
EntityAttributeAPI.addEntityAttribute(entity, ATTRIBUTE_SOURCE, attributes);
}
private Map<String, Double> readAttributes(MythicMob mythicMob) {
MythicConfig config = mythicMob.getConfig();
Map<String, Double> attributes = new HashMap<>();
if (config == null || !config.isConfigurationSection(ATTRIBUTE_SECTION)) {
return attributes;
}
Set<String> keys = config.getKeys(ATTRIBUTE_SECTION);
if (keys == null || keys.isEmpty()) {
return attributes;
}
for (String key : keys) {
String path = ATTRIBUTE_SECTION + "." + key;
if (!isNumeric(config, path)) {
Bukkit.getLogger().warning("[日志 - 错误] MythicMobs怪物 " + mythicMob.getInternalName()
+ " 的属性 " + key + " 不是有效数字。");
continue;
}
if (!EntityAttributeAPI.isSupportedAttribute(key)) {
Bukkit.getLogger().warning("[日志 - 错误] MythicMobs怪物 " + mythicMob.getInternalName()
+ " 的属性 " + key + " 不受AuMyItems支持。");
continue;
}
Bukkit.getConsoleSender().sendMessage(" - " + key + ": " + config.getDouble(path));
attributes.put(key, config.getDouble(path));
}
if(MyItems.debug){
Bukkit.getConsoleSender().sendMessage("[日志 - 输出] MythicMobId: " + mythicMob.getInternalName());
for (String key: attributes.keySet()){
Bukkit.getConsoleSender().sendMessage(" - " + key + ": " + attributes.get(key));
}
}
return attributes;
}
private boolean isNumeric(MythicConfig config, String path) {
return config.isDouble(path) || config.isInt(path);
}
}

View File

@@ -1,6 +1,7 @@
package com.io.yaohun.myitems.listener;
import com.io.yaohun.myitems.MyItems;
import com.io.yaohun.myitems.api.SuitLoreAPI;
import com.io.yaohun.myitems.manage.AttributeManager;
import com.io.yaohun.myitems.manage.SuitManager;
import org.bukkit.Bukkit;
@@ -131,8 +132,9 @@ public class SuitListener implements Listener {
return;
}
boolean changed = suitManager.refreshPlayerSuitState(player, sendMessage);
if (!changed) {
boolean loreChanged = SuitLoreAPI.refreshEquipmentLore(player);
boolean suitChanged = suitManager.refreshPlayerSuitState(player, sendMessage);
if (!loreChanged && !suitChanged) {
return;
}

View File

@@ -108,16 +108,16 @@ public class SuitManager {
disabled.removeAll(newSuits);
playerActiveSuitMap.put(player.getUniqueId(), new HashSet<>(newSuits));
if (sendMessage) {
for (String suitId : enabled) {
player.sendMessage(ChatColor.GREEN + "[MyItems] 套装属性已生效: " + ChatColor.WHITE + getDisplayName(suitId));
}
for (String suitId : disabled) {
player.sendMessage(ChatColor.RED + "[MyItems] 套装属性已失效: " + ChatColor.WHITE + getDisplayName(suitId));
if(MyItems.debug) {
if (sendMessage) {
for (String suitId : enabled) {
player.sendMessage(ChatColor.GREEN + "[MyItems] 套装属性已生效: " + ChatColor.WHITE + getDisplayName(suitId));
}
for (String suitId : disabled) {
player.sendMessage(ChatColor.RED + "[MyItems] 套装属性已失效: " + ChatColor.WHITE + getDisplayName(suitId));
}
}
}
return true;
}
@@ -137,6 +137,19 @@ public class SuitManager {
return activeSuits;
}
public int getSuitCount(Player player, String suitId) {
if (suitId == null || suitId.isEmpty()) {
return 0;
}
return getSuitCounts(player).getOrDefault(suitId, 0);
}
public int getSuitRequire(String suitId) {
SuitTemplate template = suitTemplateMap.get(suitId);
return template == null ? 0 : template.getRequireAmount();
}
public void clearPlayerState(Player player) {
if (player != null) {
playerActiveSuitMap.remove(player.getUniqueId());

View File

@@ -10,6 +10,10 @@ public final class AttributeKeys {
new NamespacedKey(MyItems.inst(), "template_id");
public static final NamespacedKey SUIT_ID =
new NamespacedKey(MyItems.inst(), "suit_id");
public static final NamespacedKey SUIT_LORE_TEMPLATE =
new NamespacedKey(MyItems.inst(), "suit_lore_template");
public static final NamespacedKey SUIT_LORE_ANCHOR =
new NamespacedKey(MyItems.inst(), "suit_lore_anchor");
public static final NamespacedKey PHYSICAL_ATTACK =
new NamespacedKey(MyItems.inst(), "physical_attack");

View File

@@ -179,6 +179,14 @@ public class ItemAttributeEditor {
return setStringData(item, AttributeKeys.SUIT_ID, suitId);
}
public static ItemStack setSuitLoreTemplate(ItemStack item, String template) {
return setStringData(item, AttributeKeys.SUIT_LORE_TEMPLATE, template);
}
public static ItemStack setSuitLoreAnchor(ItemStack item, String anchor) {
return setStringData(item, AttributeKeys.SUIT_LORE_ANCHOR, anchor);
}
private static NamespacedKey getKey(AttributeType type) {
switch (type) {
case PHYSICAL_ATTACK:

View File

@@ -235,6 +235,14 @@ public final class ItemAttributeUtil {
return readString(item, AttributeKeys.SUIT_ID);
}
public static String readSuitLoreTemplate(ItemStack item) {
return readString(item, AttributeKeys.SUIT_LORE_TEMPLATE);
}
public static String readSuitLoreAnchor(ItemStack item) {
return readString(item, AttributeKeys.SUIT_LORE_ANCHOR);
}
public static boolean hasAnyAttribute(ItemStack item) {
if (item == null || item.getType() == Material.AIR || !item.hasItemMeta()) {
return false;

View File

@@ -1,10 +1,11 @@
name: AuMyItems
main: com.io.yaohun.myitems.MyItems
version: 1.1.3
version: 1.2.0
api-version: 1.21
authors: [YaoHunYa]
depend:
- CraftEngine
- MythicMobs
commands:
att:
repair: