Rename internal CMagicGem implementation
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package cn.infstar.magicgem.expression;
|
||||
|
||||
import cn.infstar.magicgem.integration.PlaceholderBridge;
|
||||
import cn.infstar.magicgem.util.EnchantmentResolver;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class DynamicExpression {
|
||||
private static final Pattern ITEM_VARIABLE = Pattern.compile("\\$(LORE|WORD|NBT|ENCHANT):([^?$]+?)(?:\\?([^$]*))?\\$", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern NUMBER = Pattern.compile("[-+]?\\d+(?:\\.\\d+)?");
|
||||
private final Expression expression;
|
||||
private final PlaceholderBridge placeholders;
|
||||
|
||||
public DynamicExpression(Expression expression, PlaceholderBridge placeholders) {
|
||||
this.expression = expression;
|
||||
this.placeholders = placeholders;
|
||||
}
|
||||
|
||||
public double evaluate(String source, Player player, ItemStack item, Map<String, Double> variables) {
|
||||
return evaluate(source, player, item, variables, false);
|
||||
}
|
||||
|
||||
public double evaluateRoman(String source, Player player, ItemStack item, Map<String, Double> variables) {
|
||||
return evaluate(source, player, item, variables, true);
|
||||
}
|
||||
|
||||
private double evaluate(String source, Player player, ItemStack item, Map<String, Double> variables, boolean roman) {
|
||||
String resolved = placeholders.resolve(player, source == null ? "0" : source);
|
||||
Matcher matcher = ITEM_VARIABLE.matcher(resolved);
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
double fallback = parseNumber(matcher.group(3), 0);
|
||||
double value = resolveItem(matcher.group(1), matcher.group(2), item, fallback, roman);
|
||||
matcher.appendReplacement(buffer, Matcher.quoteReplacement(Double.toString(value)));
|
||||
}
|
||||
matcher.appendTail(buffer);
|
||||
Map<String, Double> normalized = new HashMap<>();
|
||||
variables.forEach((key, value) -> {
|
||||
normalized.put(key, value);
|
||||
normalized.put(key.toLowerCase(Locale.ROOT), value);
|
||||
});
|
||||
return expression.evaluate(buffer.toString(), normalized);
|
||||
}
|
||||
|
||||
public boolean test(String source, Player player, ItemStack item, Map<String, Double> variables) {
|
||||
return Math.abs(evaluate(source, player, item, variables)) > 1.0E-9;
|
||||
}
|
||||
|
||||
private double resolveItem(String type, String key, ItemStack item, double fallback, boolean roman) {
|
||||
if (item == null || item.getType().isAir()) return fallback;
|
||||
return switch (type.toUpperCase(Locale.ROOT)) {
|
||||
case "LORE" -> lore(item, key, fallback, roman);
|
||||
case "WORD" -> word(item, key, fallback);
|
||||
case "NBT" -> nbt(item, key, fallback);
|
||||
case "ENCHANT" -> enchant(item, key, fallback);
|
||||
default -> fallback;
|
||||
};
|
||||
}
|
||||
|
||||
private double word(ItemStack item, String expected, double value) {
|
||||
if (!item.hasItemMeta()) return 0;
|
||||
String cleanExpected = strip(expected);
|
||||
if (item.getItemMeta().hasDisplayName() && strip(item.getItemMeta().getDisplayName()).contains(cleanExpected)) return value;
|
||||
if (item.getItemMeta().hasLore() && item.getItemMeta().getLore() != null) {
|
||||
for (String line : item.getItemMeta().getLore()) if (strip(line).contains(cleanExpected)) return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private double lore(ItemStack item, String marker, double fallback, boolean roman) {
|
||||
if (!item.hasItemMeta() || !item.getItemMeta().hasLore() || item.getItemMeta().getLore() == null) return fallback;
|
||||
String cleanMarker = strip(marker);
|
||||
for (String line : item.getItemMeta().getLore()) {
|
||||
String clean = strip(line);
|
||||
int index = clean.indexOf(cleanMarker);
|
||||
if (index < 0) continue;
|
||||
Matcher number = NUMBER.matcher(clean.substring(index + cleanMarker.length()));
|
||||
if (number.find()) return parseNumber(number.group(), fallback);
|
||||
if (roman) {
|
||||
Matcher numeral = Pattern.compile("(?i)\\b[IVXLCDM]+\\b")
|
||||
.matcher(clean.substring(index + cleanMarker.length()));
|
||||
if (numeral.find()) return parseRoman(numeral.group(), fallback);
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private double nbt(ItemStack item, String key, double fallback) {
|
||||
try {
|
||||
return NBT.get(item, nbt -> {
|
||||
if (!nbt.hasTag(key)) return fallback;
|
||||
return switch (nbt.getType(key)) {
|
||||
case NBTTagByte -> nbt.getByte(key).doubleValue();
|
||||
case NBTTagShort -> nbt.getShort(key).doubleValue();
|
||||
case NBTTagInt -> nbt.getInteger(key).doubleValue();
|
||||
case NBTTagLong -> nbt.getLong(key).doubleValue();
|
||||
case NBTTagFloat -> nbt.getFloat(key).doubleValue();
|
||||
case NBTTagDouble -> nbt.getDouble(key);
|
||||
default -> parseNumber(nbt.getString(key), fallback);
|
||||
};
|
||||
});
|
||||
} catch (RuntimeException exception) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private double enchant(ItemStack item, String key, double fallback) {
|
||||
Enchantment enchantment = EnchantmentResolver.resolve(key);
|
||||
return enchantment == null ? fallback : item.getEnchantmentLevel(enchantment);
|
||||
}
|
||||
|
||||
private String strip(String value) {
|
||||
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', value == null ? "" : value));
|
||||
}
|
||||
|
||||
private double parseNumber(String value, double fallback) {
|
||||
try { return value == null || value.isBlank() ? fallback : Double.parseDouble(value); }
|
||||
catch (NumberFormatException ignored) { return fallback; }
|
||||
}
|
||||
|
||||
private double parseRoman(String value, double fallback) {
|
||||
if (value == null || value.isBlank()) return fallback;
|
||||
int total = 0;
|
||||
int previous = 0;
|
||||
String normalized = value.toUpperCase(Locale.ROOT);
|
||||
for (int index = normalized.length() - 1; index >= 0; index--) {
|
||||
int current = switch (normalized.charAt(index)) {
|
||||
case 'I' -> 1; case 'V' -> 5; case 'X' -> 10; case 'L' -> 50;
|
||||
case 'C' -> 100; case 'D' -> 500; case 'M' -> 1000; default -> 0;
|
||||
};
|
||||
if (current == 0) return fallback;
|
||||
total += current < previous ? -current : current;
|
||||
previous = current;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user