三库归位登录凭证/用户组/Php,处罚预告按规则档位修正,解禁与重置不再动人机验证
Check Source / check (push) Successful in 2s
Auto Release / build (push) Successful in 2m4s
Simple Test / test (push) Successful in 1s
Test Env / test (push) Successful in 1s

1) login.db 创建即入 登录凭证/、usergroup.db 入 用户组/、web_sync.db 入 Php/(WebManager 5处统一走 webSyncDbFile()),根目录存量由 migrateRootDataFiles 启动最早期整组迁移(.db+-shm+-wal 同进同退,失败整组回滚);2) nextPunishHint 改为按 applyPunish同款判据(violation>=阈值取最高档)计算下一次违规真正命中的档位与配置时长,修复旧实现取 k>违规数 导致第3次违规就预告第6档15分钟、预告与实际处罚长期对不上的问题;3) unmutePlayer/resetPlayer 移除 markReverify 调用,解禁与重置发言违规不再重置人机验证(resetPlayer 顺带清 DB muted_until,避免重置后重启禁言复活)
This commit is contained in:
youpaishidifu
2026-10-08 18:57:51 +08:00
parent 47301edaed
commit cbfdfb016b
5 changed files with 67 additions and 30 deletions
+36 -22
View File
@@ -1126,7 +1126,8 @@ public class ChatFilterManager {
// ★ 2026-10-08 用户裁定:玩家已通过人机验证后,禁言到期自动解禁
// **不再**吊销验证状态。此前这里调 markReverify 导致
// 「验证码通过 → 被禁言 → 到期解禁 → 又要重验」的死循环。
// 仅显式 /chat unmute 与 /chat reset 才吊销(见 unmutePlayer/resetPlayer)。
// 2026-10-08 用户裁定再收紧:命令解禁 /chat unmute 与重置 /chat reset
// 也【不再】吊销——解禁/重置发言违规 与 人机验证 两件事彻底隔开。
return false;
}
return true;
@@ -1309,13 +1310,15 @@ public class ChatFilterManager {
muteIssuers.remove(name);
muteStarts.remove(name);
clearMuteDb(name);
// ★ 解禁≠解除人机验证(2026-10-08)
markReverify(name);
// ★ 解禁≠解除人机验证(2026-10-08 用户裁定,且必须落到代码上):
// 解禁只清禁言状态,绝不触碰人机验证(markReverify 调用已移除)。
}
/**
* ★ 解禁(命令解禁/禁言到期/重置)→ 吊销人机验证:
* ★ 显式重置人机验证(2026-10-08 起无内部调用方,保留为对外能力):
* 移出已验证名单、清掉挂起的题与缓存消息,下次发言必须重新过人机验证。
* 注意:unmutePlayer(解禁)/ resetPlayer(重置发言违规)已按用户裁定
* 与本方法解耦,不再调用。
*/
public void markReverify(String name) {
reverifyRequired.add(name);
@@ -1411,36 +1414,47 @@ public class ChatFilterManager {
}
public void resetPlayer(String name) {
boolean wasMuted = mutedPlayers.remove(name) != null;
mutedPlayers.remove(name);
muteReasons.remove(name);
muteIssuers.remove(name);
muteStarts.remove(name);
violationCount.remove(name);
// ★ 显式 /chat reset = 人为强制重置 → 吊销人机验证(合理)。
// 注意与 isMuted() 的「到期自动解禁」区分:后者不吊销(见 98-a)。
if (wasMuted) {
markReverify(name);
}
clearMuteDb(name); // 同步清 DB 的 muted_until,避免重启后禁言复活
// ★ 2026-10-08 用户裁定:「重置发言违规」与「重置人机验证」彻底隔开——
// 这里只清禁言与违规计数,不再调用 markReverify,
// 人机验证状态(verifiedPlayers/reverifyRequired 等)原样保留。
}
/** 下一档违规将触发的处罚描述(命中时给玩家预告),无更高档返回 null */
/**
* 下一次违规真正会吃到的处罚描述(命中时给玩家预告),
* 没达到任何处罚阈值时返回 null。
* ★ 2026-10-08 修正(用户反馈「不是每次违规都罚15分钟,要按规则配置」):
* 旧实现取「大于当前计数的下一个阈值」(k > violation),
* 但 applyPunishment 的判据是 violation >= 阈值 取最高档——
* 例如规则 3:mute:300 / 6:mute:900 时,第3次违规实际按第3档禁言5分,
* 旧预告却已跳到第6档「禁言15分」,且第4、5次也一直报15分,
* 预告与实际处罚长期对不上。这里改为按与 applyPunishment 完全相同的
* 判据,计算「计数 + 1」时真正命中的那一档,时长取该档配置。
* 另:文案只报处罚档位、不带「第 N 次违规」前缀——
* 否则与上一行的「本次为第 N 次违规」并列会被读成计数跳号。
*/
public String nextPunishHint(int violation) {
int nextKey = Integer.MAX_VALUE;
int target = violation + 1; // 下一次违规时的计数
int bestKey = Integer.MIN_VALUE;
for (Integer k : punishmentRules.keySet()) {
if (k > violation && k < nextKey) {
nextKey = k;
if (k <= target && k > bestKey) {
bestKey = k; // 与 applyPunishment 同款:violation >= 阈值 取最高档
}
}
if (nextKey == Integer.MAX_VALUE) {
return null;
if (bestKey == Integer.MIN_VALUE) {
return null; // 尚未达到任何处罚阈值
}
String type = punishmentRules.get(nextKey);
int dur = punishmentDurations.getOrDefault(nextKey, muteDuration);
String type = punishmentRules.get(bestKey);
int dur = punishmentDurations.getOrDefault(bestKey, muteDuration);
String cn = switchPunishType(type);
if ("mute".equals(type)) {
cn += " " + fmtDuration(dur);
}
// ★ 2026-10-08:不再返回「第 N 次违规」前缀。
// 原文案「第3次违规: 禁言5分」紧跟在「(第 2 次违规)」之后,
// 两行并列会被读成计数 2→6 跳号(实际计数是 1→2→3,未跳)。
// 次数只在「(第 N 次违规)」一处出现,避免重复计数视觉。
return cn;
}
@@ -21,8 +21,12 @@ public class DatabaseManager {
public void init() {
try {
Class.forName("org.sqlite.JDBC");
File dbFile = new File(dataFolder,
"login.db");
// ★ 2026-10-08 归位:login.db 创建即放入「登录凭证/」;
// 根目录存量由 Main.migrateRootDataFiles() 启动最早期整组迁移
// (.db + -shm + -wal 同进同退,严禁人工移动)。
File dbDir = new File(dataFolder, "登录凭证");
dbDir.mkdirs();
File dbFile = new File(dbDir, "login.db");
db = DriverManager.getConnection(
"jdbc:sqlite:"
+ dbFile.getAbsolutePath());
+4
View File
@@ -1009,6 +1009,10 @@ public class Main extends JavaPlugin
{"maxsell_config.txt", "shop", "0"},
// #99 quest_data.db 归入「任务面板」(任务进度数据)
{"quest_data.db", "任务面板", "1"},
// #100 2026-10-08 三库归位(用户指令:代码层面迁移)
{"login.db", "登录凭证", "1"},
{"usergroup.db", "用户组", "1"},
{"web_sync.db", "Php", "1"},
};
for (String[] m : moves) {
boolean group = "1".equals(m[2]);
@@ -35,7 +35,10 @@ public class UserGroupManager {
private void initDB() {
try {
Class.forName("org.sqlite.JDBC");
File dbFile = new File(plugin.getDataFolder(), "usergroup.db");
// ★ 2026-10-08 归位:usergroup.db 创建即放入「用户组/」
File dbDir = new File(plugin.getDataFolder(), "用户组");
dbDir.mkdirs();
File dbFile = new File(dbDir, "usergroup.db");
db = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
Statement st = db.createStatement();
st.execute("PRAGMA journal_mode=WAL");
+17 -5
View File
@@ -1608,7 +1608,7 @@ public class WebManager {
try {
Class.forName("org.sqlite.JDBC");
File dataFolder = plugin.getDataFolder();
File dbFile = new File(dataFolder, "web_sync.db");
File dbFile = webSyncDbFile(dataFolder);
if (!dbFile.exists()) {
dbFile.createNewFile();
}
@@ -2170,7 +2170,7 @@ public class WebManager {
// ★ 检查sync_requests表(来自PHP端的即时同步请求)
try {
File dataFolder = plugin.getDataFolder();
File dbFile = new File(dataFolder, "web_sync.db");
File dbFile = webSyncDbFile(dataFolder);
if (dbFile.exists()) {
Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
Statement stmt = conn.createStatement();
@@ -7378,7 +7378,7 @@ public class WebManager {
return;
}
try {
File dbFile = new File(plugin.getDataFolder(), "web_sync.db");
File dbFile = webSyncDbFile(plugin.getDataFolder());
java.sql.Connection conn = java.sql.DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
java.sql.Statement st = conn.createStatement();
st.execute("PRAGMA busy_timeout=8000");
@@ -7391,10 +7391,22 @@ public class WebManager {
}
/**
* ★ 2026-10-08 归位:web_sync.db 创建即放入「Php/」子目录。
* 根目录存量由 Main.migrateRootDataFiles() 启动最早期整组迁移
* (.db + -shm + -wal 同进同退,严禁人工移动)。
* 所有取连接处统一走本方法,避免路径分叉。
*/
private static File webSyncDbFile(File dataFolder) {
File dir = new File(dataFolder, "Php");
dir.mkdirs();
return new File(dir, "web_sync.db");
}
private void loadLastSyncedTxTime() {
if (lastSyncedTxTime > 0) return;
try {
File dbFile = new File(plugin.getDataFolder(), "web_sync.db");
File dbFile = webSyncDbFile(plugin.getDataFolder());
if (!dbFile.exists()) return;
java.sql.Connection conn = java.sql.DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
java.sql.Statement st = conn.createStatement();
@@ -7412,7 +7424,7 @@ public class WebManager {
private void saveLastSyncedTxTime(long time) {
try {
File dbFile = new File(plugin.getDataFolder(), "web_sync.db");
File dbFile = webSyncDbFile(plugin.getDataFolder());
java.sql.Connection conn = java.sql.DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
java.sql.Statement st = conn.createStatement();
st.execute("PRAGMA busy_timeout=8000");