feat: 新增模糊匹配识别

This commit is contained in:
ypsdf1
2026-05-23 20:41:37 +08:00
parent 0a6c8dbe20
commit 8b69df2154
+151 -78
View File
@@ -190,7 +190,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
private String colorize(String s) {
if (s == null) return "";
return s.replaceAll("&([0-9a-fk-orA-FK-OR])", "\u00a7$1");
return s.replaceAll("&([0-9a-fk-orA-FK-OR])", "§$1");
}
@Override
@@ -560,7 +560,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
text = text.replaceAll("^['\"](.*)['\"]$", "$1").trim();
text = normalizeText(text);
log("[SDF1-诊断-动作] 输入: [" + text + "]");
text = text.replace('\uff0d', '-').replace('\u2013', '-').replace('\u2014', '-').replace('\uff5e', '~');
text = text.replace('-', '-').replace('–', '-').replace('—', '-').replace('~', '~');
String norm = normalizeAllDigits(text);
norm = normalizeEnglishNumbers(norm);
@@ -578,7 +578,11 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (bondBlindM.find()) {
int bmin = Integer.parseInt(bondBlindM.group(1));
int bmax = Integer.parseInt(bondBlindM.group(2));
if (bmin > bmax) { int t2 = bmin; bmin = bmax; bmax = t2; }
if (bmin > bmax) {
int t2 = bmin;
bmin = bmax;
bmax = t2;
}
block.put("_债券盲盒", "true");
block.put("_债券盲盒_min", String.valueOf(bmin));
block.put("_债券盲盒_max", String.valueOf(bmax));
@@ -591,7 +595,11 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (bondR.find()) {
int bmin = Integer.parseInt(bondR.group(1));
int bmax = Integer.parseInt(bondR.group(2));
if (bmin > bmax) { int t2 = bmin; bmin = bmax; bmax = t2; }
if (bmin > bmax) {
int t2 = bmin;
bmin = bmax;
bmax = t2;
}
block.put("_债券盲盒", "true");
block.put("_债券盲盒_min", String.valueOf(bmin));
block.put("_债券盲盒_max", String.valueOf(bmax));
@@ -600,7 +608,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
}
// 固定发债券(非盲盒)
if (!"true".equals(block.get("_债券盲盒"))) {
Matcher bondM = Pattern.compile("(\\d+)\\s*个?\\s*债券").matcher(norm);
Matcher bondM = Pattern.compile("(\\d+)\\s*[个块枚元]?" + "\\s*债券").matcher(norm);
if (bondM.find()) {
int bondAmt = Integer.parseInt(bondM.group(1));
block.put("_发债券", String.valueOf(bondAmt));
@@ -761,10 +769,12 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
}
}
// ★ 发钱检测(排除债券,债券已独立处理)
boolean isGive = !isTake && (norm.contains("给") || norm.contains("奖")
|| norm.contains("发") || norm.contains("加") || norm.contains("赏")
|| norm.contains("赠送") || norm.contains("返"));
// ★ 发钱检测(排除债券、排除扣钱)
boolean isGive = !isTake && !norm.contains("债券")
&& (norm.contains("给") || norm.contains("奖")
|| norm.contains("发") || norm.contains("加")
|| norm.contains("赏") || norm.contains("赠送")
|| norm.contains("返"));
if (isGive) {
double amt = extractMoneyExcludingSlots(norm);
if (amt > 0) {
@@ -773,8 +783,6 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
}
}
}
private String safeStr(String s) { return s == null ? "" : s.trim(); }
private int safeInt(String s) {
@@ -803,7 +811,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= '\uFF10' && c <= '\uFF19') {
if (c >= '0' && c <= '9') {
sb.append((char)(c - 0xFF10 + '0'));
} else if (c == '\uFF0E') {
sb.append('.');
@@ -927,9 +935,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
private String normalizeText(String s) {
if (s == null) return "";
return s.replace('\uff0d', '-').replace('\u2013', '-').replace('\u2014', '-')
.replace('\u2212', '-').replace('\uff5e', '~')
.replace("\u200b", "").replace("\ufeff", "");
return s.replace('-', '-').replace('–', '-').replace('—', '-')
.replace('−', '-').replace('~', '~')
.replace("​", "").replace("", "");
}
private int parseChineseNum(String s) {
@@ -1260,14 +1268,91 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
try {
Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
Objective obj = board.getObjective(cfgCdkObj);
if (obj == null) { if (!cdksWarned) { log("[计分板] 找不到: " + cfgCdkObj); cdksWarned = true; } return -1; }
if (obj == null) {
if (!cdksWarned) { log("[计分板] 找不到: " + cfgCdkObj); cdksWarned = true; }
return -1;
}
cdksWarned = false;
// 第一轮:精确匹配
Score s = obj.getScore(code);
if (!s.isScoreSet()) return -1;
return s.getScore();
if (s.isScoreSet()) return s.getScore();
// 第二轮:模糊匹配 —— 去分隔符 + 统一大小写
String normInput = normalizeForCompare(code);
for (String entry : board.getEntries()) {
Score sc = obj.getScore(entry);
if (sc.isScoreSet()) {
if (normalizeForCompare(entry).equals(normInput)) {
log("[模糊匹配] \"" + code + "\" -> 标准码 \""
+ entry + "\" 分值=" + sc.getScore());
return sc.getScore();
}
}
}
return -1;
} catch (Exception e) { return -1; }
}
/**
* 查找口令,返回 [分值, 标准码]
* 玩家输入 aaabbbbcccc → 标准码 AAAA-BBBB-CCCC
* 如果精确匹配就用原码,模糊匹配就返回计分板上的原始条目
*/
private Object[] lookupScoreAndCanonical(String code) {
if (!configLoaded || cfgCdkObj.isEmpty())
return new Object[]{ -1, code };
try {
Scoreboard board =
Bukkit.getScoreboardManager().getMainScoreboard();
Objective obj = board.getObjective(cfgCdkObj);
if (obj == null) {
if (!cdksWarned) {
log("[计分板] 找不到: " + cfgCdkObj);
cdksWarned = true;
}
return new Object[]{ -1, code };
}
cdksWarned = false;
// 第一轮:精确匹配
Score s = obj.getScore(code);
if (s.isScoreSet()) {
return new Object[]{ s.getScore(), code };
}
// 第二轮:模糊匹配
String normInput = normalizeForCompare(code);
for (String entry : board.getEntries()) {
Score sc = obj.getScore(entry);
if (sc.isScoreSet()) {
if (normalizeForCompare(entry).equals(normInput)) {
log("[模糊匹配] \"" + code
+ "\" -> 标准码 \"" + entry
+ "\" 分值=" + sc.getScore());
return new Object[]{ sc.getScore(), entry };
}
}
}
return new Object[]{ -1, code };
} catch (Exception e) {
return new Object[]{ -1, code };
}
}
/**
* 去除所有分隔符,统一转小写
* "AAAA-BBBB-CCCC" → "aaaabbbbcccc"
* "aaabbbbcccc" → "aaaabbbbcccc"
* "aAa-BbBb-CcCc" → "aaaabbbbcccc"
* "AAAA BB BB CC CC" → "aaaabbbbcccc"
*/
private String normalizeForCompare(String s) {
if (s == null) return "";
return s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
}
private void consumeCode(String code, boolean deleteCode) {
if (!deleteCode) return;
log("[删除] 口令: \"" + code + "\" 目标: " + cfgCdkObj);
@@ -1664,73 +1749,61 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
consumeCode(code, true);
}
private boolean tryBondRedeem(Player p, String code) {
Connection bdb = getBondDb();
if (bdb == null) return false;
private boolean tryBondRedeem(Player p,
String code) {
try {
PreparedStatement ps = bdb.prepareStatement(
"SELECT amount, used FROM cdk WHERE code=?");
ps.setString(1, code);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
Plugin sdf1 = Bukkit.getPluginManager()
.getPlugin("Sdf1_login");
if (sdf1 == null || !sdf1.isEnabled())
return false;
}
int amount = rs.getInt("amount");
int used = rs.getInt("used");
rs.close();
ps.close();
if (used == 1) {
p.sendMessage(colorize("&c此兑换码已被使用"));
java.lang.reflect.Method m =
sdf1.getClass().getMethod(
"redeemBondForExternal",
String.class,
String.class);
Object result = m.invoke(sdf1,
p.getName(), code);
String res = result != null
? result.toString()
: "fail:null";
if (res.startsWith("success:")) {
String[] parts = res.split(":");
int amount =
Integer.parseInt(parts[1]);
int bef =
Integer.parseInt(parts[2]);
int aft =
Integer.parseInt(parts[3]);
p.sendMessage(colorize(
"&6&l[债券] &e&l恭喜!获得 &c&l"
+ amount + " &e&l债券!"));
p.sendMessage(colorize(
"&7余额: &e" + bef
+ " &7-> &a" + aft));
log("[债券] " + p.getName()
+ " 兑换 " + amount + " 债券");
return true;
}
PreparedStatement up = bdb.prepareStatement(
"UPDATE cdk SET used=1, used_by=?, used_time=? WHERE code=?");
up.setString(1, p.getName());
up.setLong(2, System.currentTimeMillis());
up.setString(3, code);
up.executeUpdate();
up.close();
int beforeBal = 0;
PreparedStatement q0 = bdb.prepareStatement(
"SELECT amount FROM bonds WHERE player_name=?");
q0.setString(1, p.getName());
ResultSet rs0 = q0.executeQuery();
if (rs0.next()) beforeBal = rs0.getInt("amount");
rs0.close(); q0.close();
int befBal = 0;
PreparedStatement q1 = bdb.prepareStatement(
"SELECT amount FROM bonds WHERE player_name=?");
q0.setString(1, p.getName());
ResultSet rs1 = q0.executeQuery();
if (rs0.next()) befBal = rs0.getInt("amount");
rs0.close(); q0.close();
PreparedStatement add = bdb.prepareStatement(
"INSERT INTO bonds(player_name, amount) VALUES(?,?) "
+ "ON CONFLICT(player_name) "
+ "DO UPDATE SET amount=amount+?");
add.setString(1, p.getName());
add.setInt(2, amount);
add.setInt(3, amount);
add.executeUpdate();
add.close();
logBondTx(p.getName(), "redeem", amount,
"", "CDK系统", "兑换码兑换",
befBal, befBal + amount);
p.sendMessage(colorize("&6&l[债券] &e&l恭喜!获得 &c&l" + amount + " &e&l债券!"));
log("[债券] " + p.getName() + " 兑换 " + amount + " 债券");
return true;
if ("fail:not_found".equals(res))
return false;
if ("fail:already_used".equals(res)) {
p.sendMessage(colorize(
"&c此兑换码已被使用"));
return true;
}
if ("fail:frozen".equals(res)) {
p.sendMessage(colorize(
"&c账户已被冻结"));
return true;
}
return false;
} catch (Exception e) {
log("[债券] 兑换异常: " + e.getMessage());
log("[债券] 反射调用失败: "
+ e.getMessage());
return false;
}
}