v18 修复快速重连:新增javaLoginRecords持久化登录记录(5分钟),检查点1放行同IP重连;添加PHP响应日志

This commit is contained in:
2026-06-25 18:44:42 +08:00
parent 329bca61a9
commit f1cd0da7d4
3 changed files with 97 additions and 12 deletions
@@ -66,6 +66,10 @@ public class LoginManager {
plugin.getDb().createUser(
name, hash, salt);
plugin.getLoggedIn().add(name);
// ★ 记录Java手动登录:5分钟内重连可直接放行(检查点1)
if (plugin.webManager != null) {
plugin.webManager.recordJavaLogin(name);
}
p.setAllowFlight(false);
p.setFlying(false);
plugin.getDb().setLoggedIn(name, true);
@@ -162,6 +166,10 @@ public class LoginManager {
name, hash);
if (matchMain) {
plugin.getLoggedIn().add(name);
// ★ 记录Java手动登录:5分钟内重连可直接放行(检查点1)
if (plugin.webManager != null) {
plugin.webManager.recordJavaLogin(name);
}
plugin.getDb().setLoggedIn(
name, true);
plugin.getDb().setLoggedIn(
@@ -207,6 +215,10 @@ public class LoginManager {
name, hash);
if (matchTemp) {
plugin.getLoggedIn().add(name);
// ★ 记录Java手动登录:5分钟内重连可直接放行(检查点1)
if (plugin.webManager != null) {
plugin.webManager.recordJavaLogin(name);
}
plugin.getDb().setLoggedIn(name, true);
p.setAllowFlight(false);
p.setFlying(false);
+12 -7
View File
@@ -1166,6 +1166,10 @@ public class Main extends JavaPlugin
}
loggedIn.add(name);
// ★ 记录Java手动登录:5分钟内重连可直接放行(检查点1)
if (webManager != null) {
webManager.recordJavaLogin(name);
}
p.setAllowFlight(false);
p.setFlying(false);
@@ -1741,14 +1745,15 @@ public class Main extends JavaPlugin
// ===== 快速重连三层检查(严格按流程图) =====
// ★ 检查点1:检查玩家是否有Java手动登录记录( loggedIn 集合)
// 注意:loggedIn在onQuit时会被清除,因此快速重连时检查点1通常失败
// 这是正常行为 — 快速重连走检查点2(isWebLoginVerified)通过IP+内存验证
if (loggedIn.contains(name)) {
getLogger().info("[Web登录] 检查点1通过: 玩家 " + name + " 有Java手动登录记录,放行");
// 继续走正常登录流程(不中断)
// ★ 检查点1:检查玩家是否有Java手动登录记录
// 优先检查loggedIn(当前在线),再检查javaLoginRecords(5分钟内重连有效)
boolean hasJavaLogin = loggedIn.contains(name) || (webManager != null && webManager.isJavaLoginRecorded(name));
if (hasJavaLogin) {
getLogger().info("[Web登录] 检查点1通过: 玩家 " + name + " 有Java登录记录,自动登录");
autoLogin(p, "java_reconnect");
return; // 检查点1通过 → 直接放行
} else {
getLogger().info("[Web登录] 检查点1失败: 玩家 " + name + " 无Java手动登录记录(正常,已在onQuit清除)");
getLogger().info("[Web登录] 检查点1失败: 玩家 " + name + " 无Java登录记录");
}
// 辅助操作:生成Web Token + 同步PHP注册数据
+73 -5
View File
@@ -55,6 +55,11 @@ public class WebManager {
private final ConcurrentHashMap<String, Long> verifiedWebLogins = new ConcurrentHashMap<>();
private static final long VERIFIED_LOGIN_EXPIRE_MS = 300000; // 5分钟过期
// ★ Java手动登录记录:playerName -> 登录时间戳(毫秒)
// 玩家通过/l命令或autoLogin成功后记录,onQuit不清除,5分钟内重连可直接放行(检查点1)
private final ConcurrentHashMap<String, Long> javaLoginRecords = new ConcurrentHashMap<>();
private static final long JAVA_LOGIN_RECORD_EXPIRE_MS = 300000; // 5分钟过期
// ★ 合并定时器错峰调度(v17:3个定时器替代6个)
private static final int TIMER_A = 0; // 注册登录 0~5秒
private static final int TIMER_B = 1; // 交易 0~10秒
@@ -2999,6 +3004,40 @@ public class WebManager {
verifiedWebLogins.remove(playerName);
}
// ==================== Java手动登录记录(检查点1持久化) ====================
/**
* 记录玩家Java手动登录成功(/l命令或autoLogin调用后)
* onQuit不清除,5分钟内重连可直接放行(检查点1)
*/
public void recordJavaLogin(String playerName) {
javaLoginRecords.put(playerName, System.currentTimeMillis());
plugin.getLogger().info("[Web登录] 记录Java登录: " + playerName + "(5分钟内重连可直接放行)");
}
/**
* 检查玩家是否有Java手动登录记录(检查点1用)
* 5分钟内有效,超时自动清除
*/
public boolean isJavaLoginRecorded(String playerName) {
Long loginTime = javaLoginRecords.get(playerName);
if (loginTime != null) {
if (System.currentTimeMillis() - loginTime > JAVA_LOGIN_RECORD_EXPIRE_MS) {
javaLoginRecords.remove(playerName);
return false;
}
return true;
}
return false;
}
/**
* 清除玩家的Java登录记录(玩家成功再次登录后调用,避免过期残留)
*/
public void clearJavaLoginRecord(String playerName) {
javaLoginRecords.remove(playerName);
}
/**
* 同步在线玩家列表到PHP端(用于Web登录状态检查)
* 注意:推送所有在线玩家(包括未登录的),PHP端通过 web_login_verified 判断是否已认证
@@ -3838,11 +3877,17 @@ public class WebManager {
// 成功 → 重置
loginPollFailCount = 0;
if (!json.contains("\"success\":true")) return;
if (!json.contains("\"success\":true")) {
plugin.getLogger().info("[Web登录确认轮询] PHP响应非success: " + json.substring(0, Math.min(200, json.length())));
return;
}
// 简单解析玩家名列表
int dataStart = json.indexOf("\"data\":");
if (dataStart < 0) return;
if (dataStart < 0) {
plugin.getLogger().info("[Web登录确认轮询] PHP响应无data字段: " + json.substring(0, Math.min(200, json.length())));
return;
}
String dataStr = json.substring(dataStart + 7);
int arrEnd = findMatchingBracket(dataStr, 0);
if (arrEnd < 0) return;
@@ -3916,15 +3961,38 @@ public class WebManager {
(now - entry.getValue()) > VERIFIED_LOGIN_EXPIRE_MS
);
}
// ★ 清理过期的Java登录记录(检查点1用)
if (javaLoginRecords.size() > 0) {
long now = System.currentTimeMillis();
javaLoginRecords.entrySet().removeIf(entry ->
(now - entry.getValue()) > JAVA_LOGIN_RECORD_EXPIRE_MS
);
}
String urlStr = webBaseUrl + "/api/sync.php?action=check_pending_web_logins&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8");
String json = doGet(urlStr);
if (json == null) return;
if (!json.contains("\"success\":true")) return;
if (json == null) {
loginPollFailCount++;
long now = System.currentTimeMillis();
if (now - lastLoginPollLogTime > POLL_LOG_INTERVAL) {
plugin.getLogger().warning("[Web密码验证轮询] GET失败 (连续失败" + loginPollFailCount + "次)");
lastLoginPollLogTime = now;
}
return;
}
// 成功 → 重置
loginPollFailCount = 0;
if (!json.contains("\"success\":true")) {
plugin.getLogger().info("[Web密码验证轮询] PHP响应非success: " + json.substring(0, Math.min(200, json.length())));
return;
}
// 解析请求列表
int dataStart = json.indexOf("\"data\":");
if (dataStart < 0) return;
if (dataStart < 0) {
plugin.getLogger().info("[Web密码验证轮询] PHP响应无data字段: " + json.substring(0, Math.min(200, json.length())));
return;
}
String dataStr = json.substring(dataStart + 7);
int arrEnd = findMatchingBracket(dataStr, 0);
if (arrEnd < 0) return;