修复: 自动登录逻辑重构+轮询间隔增大降低DB锁
This commit is contained in:
@@ -1742,11 +1742,13 @@ public class Main extends JavaPlugin
|
||||
// ===== 快速重连三层检查(严格按流程图) =====
|
||||
|
||||
// ★ 检查点1:检查玩家是否有Java手动登录记录( loggedIn 集合)
|
||||
// 注意:loggedIn在onQuit时会被清除,因此快速重连时检查点1通常失败
|
||||
// 这是正常行为 — 快速重连走检查点2(isWebLoginVerified)通过IP+内存验证
|
||||
if (loggedIn.contains(name)) {
|
||||
getLogger().info("[Web登录] 检查点1通过: 玩家 " + name + " 有Java手动登录记录,放行");
|
||||
// 继续走正常登录流程(不中断)
|
||||
} else {
|
||||
getLogger().info("[Web登录] 检查点1失败: 玩家 " + name + " 无Java手动登录记录");
|
||||
getLogger().info("[Web登录] 检查点1失败: 玩家 " + name + " 无Java手动登录记录(正常,已在onQuit清除)");
|
||||
}
|
||||
|
||||
// 辅助操作:生成Web Token + 同步PHP注册数据
|
||||
@@ -1757,137 +1759,32 @@ public class Main extends JavaPlugin
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 检查点2:检查服务器内存中是否有该玩家来自PHP的验证请求
|
||||
if (webManager != null && webManager.isWebLoginVerified(name)) {
|
||||
getLogger().info("[Web登录] 检查点2通过: 玩家 " + name + " 内存中有PHP验证记录,自动登录");
|
||||
// ★ 同IP判断:只作为开启自动登录验证的钥匙,不作为自动登录依据
|
||||
boolean sameIP = canAutoLogin(p);
|
||||
if (!sameIP) {
|
||||
// 不同IP → 跳过检查点2,直接强制密码验证
|
||||
getLogger().info("[Web登录] 同IP检查: 玩家 " + name + " IP不同,跳过快速重连验证");
|
||||
} else {
|
||||
getLogger().info("[Web登录] 同IP检查: 玩家 " + name + " IP相同,允许快速重连验证");
|
||||
}
|
||||
|
||||
// ★ 检查点2:只有同IP才检查服务器内存中是否有该玩家来自PHP的验证请求
|
||||
if (sameIP && webManager != null && webManager.isWebLoginVerified(name)) {
|
||||
getLogger().info("[Web登录] 检查点2通过: 玩家 " + name + " 同IP且内存中有PHP验证记录,自动登录");
|
||||
webManager.clearWebLoginVerified(name);
|
||||
autoLogin(p, "web_password");
|
||||
return; // 检查点2通过 → 直接放行,不继续后面流程
|
||||
} else {
|
||||
getLogger().info("[Web登录] 检查点2失败: 玩家 " + name + " 内存中无PHP验证记录");
|
||||
if (sameIP) {
|
||||
getLogger().info("[Web登录] 检查点2失败: 玩家 " + name + " 同IP但内存中无PHP验证记录");
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 检查点3:上述2路验证都失败 → 强制重新验证密码(走正常登录流程)
|
||||
getLogger().info("[Web登录] 检查点3: 上述2路验证都失败,强制重新验证密码");
|
||||
|
||||
// 强制重发资源包(清掉客户端拒绝记录)
|
||||
Bukkit.getScheduler()
|
||||
.runTaskLater(this, () -> {
|
||||
// ★ 资源包:只发送一次,延迟3秒确保客户端就绪
|
||||
if (radio != null) {
|
||||
final Player jp = p;
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
this, () -> {
|
||||
if (jp.isOnline()) {
|
||||
radio.sendResourcePack(jp);
|
||||
}
|
||||
}, 60L);
|
||||
}
|
||||
|
||||
}, 20L);
|
||||
// 重置聊天输入状态(防止上次退出时残留)
|
||||
chatInput.reset(p);
|
||||
if (needsPasswordChange.contains(name))
|
||||
needsPasswordChange.remove(name);
|
||||
// 改完了直接打包,要打sdf1一起
|
||||
lastActivity.put(p.getUniqueId(),
|
||||
System.currentTimeMillis());
|
||||
if (needsPasswordChange.contains(name))
|
||||
needsPasswordChange.remove(name);
|
||||
|
||||
boolean isBedrock =
|
||||
verification.isBedrockPlayer(p);
|
||||
boolean isOnlineMode =
|
||||
verification.isOnlineMode();
|
||||
|
||||
// ★ 登录阶段始终允许飞行,防止悬空被踢出
|
||||
p.setAllowFlight(true);
|
||||
|
||||
if (!db.userExists(name)) {
|
||||
if (config.maxAccountsPerIP > 0
|
||||
&& ip != null
|
||||
&& !ipGroup.canRegister(ip)) {
|
||||
p.kickPlayer(
|
||||
buildIPKickMessage(p, ip));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!"manual".equals(config.approvalMode)
|
||||
&& !db.userExists(name)) {
|
||||
AccountRequestManager.Request req =
|
||||
accountRequest.createRequest(
|
||||
name, name, ip);
|
||||
if (req != null) {
|
||||
p.kickPlayer(
|
||||
config.msg("need_approval")
|
||||
.replace("{id}",
|
||||
String.valueOf(
|
||||
req.id)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// [ADDED] 资源包(延迟发送,不强制)
|
||||
// ★ 资源包:只发送一次,延迟3秒确保客户端就绪
|
||||
if (radio != null) {
|
||||
final Player jp = p;
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
this, () -> {
|
||||
if (jp.isOnline()) {
|
||||
radio.sendResourcePack(jp);
|
||||
}
|
||||
}, 60L);
|
||||
}
|
||||
|
||||
if (isOnlineMode) {
|
||||
autoLogin(p, "premium");
|
||||
return;
|
||||
}
|
||||
if (isBedrock) {
|
||||
autoLogin(p, "bedrock");
|
||||
return;
|
||||
}
|
||||
// ★ 关键安全修复:快速重连也必须检查Java是否有Web登录验证记录
|
||||
// 否则PHP假密码登录成功后,玩家快速重连会被盲目放行
|
||||
if (webManager != null && webManager.isWebLoginVerified(name)) {
|
||||
getLogger().info("[Web登录] 快速重连检查: 玩家 " + name + " 有Java验证记录,放行");
|
||||
webManager.clearWebLoginVerified(name);
|
||||
autoLogin(p, "web_password");
|
||||
return;
|
||||
} else {
|
||||
getLogger().info("[Web登录] 快速重连检查: 玩家 " + name + " 无Java验证记录,拒绝快速重连");
|
||||
}
|
||||
// ★ 关键安全修复:快速重连时必须检查Java是否有Web登录验证记录
|
||||
// 如果玩家在Web端通过Java密码验证登录过,5分钟内重连直接放行
|
||||
// 如果没有Java验证记录 → 拒绝快速重连(防止PHP假密码绕过)
|
||||
if (webManager != null && webManager.isWebLoginVerified(name)) {
|
||||
getLogger().info("[Web登录] 快速重连检查: 玩家 " + name + " 有Java验证记录,放行");
|
||||
webManager.clearWebLoginVerified(name);
|
||||
autoLogin(p, "web_password");
|
||||
return;
|
||||
} else {
|
||||
getLogger().info("[Web登录] 快速重连检查: 玩家 " + name + " 无Java验证记录,拒绝快速重连");
|
||||
}
|
||||
if (canAutoLogin(p)) {
|
||||
autoLogin(p, "ip_reconnect");
|
||||
return;
|
||||
}
|
||||
afk.remove(p.getUniqueId());
|
||||
afk.recordAction(p.getUniqueId());
|
||||
hideInventoryDelayed(p, 0);
|
||||
// [ADDED] 发送资源包
|
||||
// ★ 资源包:只发送一次,延迟3秒确保客户端就绪
|
||||
if (radio != null) {
|
||||
final Player jp = p;
|
||||
Bukkit.getScheduler().runTaskLater(
|
||||
this, () -> {
|
||||
if (jp.isOnline()) {
|
||||
radio.sendResourcePack(jp);
|
||||
}
|
||||
}, 60L);
|
||||
}
|
||||
|
||||
|
||||
// [ADDED] 发送资源包(延迟5秒确保客户端就绪)
|
||||
// ★ 资源包:只发送一次,延迟3秒确保客户端就绪
|
||||
if (radio != null) {
|
||||
final Player jp = p;
|
||||
|
||||
@@ -1357,11 +1357,11 @@ public class WebManager {
|
||||
|
||||
checkSyncNotify();
|
||||
}
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(5), 20L * randomIntervalSeconds(5)); // activeSync 5±5秒
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(10), 20L * randomIntervalSeconds(10)); // activeSync调度 10±3秒
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易高频轮询:每5秒检查PHP端是否有待处理交易
|
||||
* 交易高频轮询:每15秒(±5)检查PHP端是否有待处理交易
|
||||
* 检测到pending交易时立即拉取,不等60-90秒的全量同步
|
||||
*/
|
||||
/**
|
||||
@@ -1424,17 +1424,19 @@ public class WebManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(8), 20L * randomIntervalSeconds(8)); // 交易轮询 8±5秒
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(15), 20L * randomIntervalSeconds(15)); // 交易轮询 15±5秒
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成定时器随机间隔(基础值 ±5秒)
|
||||
* 生成定时器随机间隔(比例偏移,基础值越大偏移越大)
|
||||
* 偏移量 = ±max(2, base/3),确保小基数也有随机性,大基数不过度离散
|
||||
* 每个请求都是独立随机数,避开并发导致的SQL锁死
|
||||
* @param baseSeconds 基础秒数
|
||||
* @return 随机秒数 [base-5, base+5],最小1秒
|
||||
* @return 随机秒数 [base-offset, base+offset],最小1秒
|
||||
*/
|
||||
private long randomIntervalSeconds(long baseSeconds) {
|
||||
long offset = (long) (Math.random() * 11) - 5; // -5 ~ +5
|
||||
long maxOffset = Math.max(2, baseSeconds / 3);
|
||||
long offset = (long) (Math.random() * (maxOffset * 2 + 1)) - maxOffset;
|
||||
return Math.max(1, baseSeconds + offset);
|
||||
}
|
||||
|
||||
@@ -1463,7 +1465,7 @@ public class WebManager {
|
||||
private volatile boolean shopStockPulling = false;
|
||||
|
||||
/**
|
||||
* 库存高频轮询:每5秒请求Web端库存变更检测接口
|
||||
* 库存高频轮询:每15秒(±5)请求Web端库存变更检测接口
|
||||
* 无改动跳过,有改动立即拉取完整库存并更新游戏
|
||||
* 60~90秒的全量同步定时器作为兜底
|
||||
*/
|
||||
@@ -1555,8 +1557,8 @@ public class WebManager {
|
||||
shopStockPollFailCount++;
|
||||
}
|
||||
}
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(8), 20L * randomIntervalSeconds(8)); // 库存轮询 8±5秒
|
||||
plugin.getLogger().info("[Web通信] 库存高频轮询已启动(每5秒)");
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(15), 20L * randomIntervalSeconds(15)); // 库存轮询 15±5秒
|
||||
plugin.getLogger().info("[Web通信] 库存高频轮询已启动(每15秒±5)");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1625,14 +1627,14 @@ public class WebManager {
|
||||
// 静默,避免刷屏
|
||||
}
|
||||
}
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(2), 20L * randomIntervalSeconds(2)); // CDK轮询 2±10秒(最小1秒)
|
||||
plugin.getLogger().info("[Web通信] CDK远程验证轮询已启动(每2秒)");
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(8), 20L * randomIntervalSeconds(8)); // CDK轮询 8±3秒
|
||||
plugin.getLogger().info("[Web通信] CDK远程验证轮询已启动(每8秒±3)");
|
||||
}
|
||||
|
||||
// ==================== 领地数据即时同步 ====================
|
||||
|
||||
/**
|
||||
* ★ 领地数据即时同步:每10秒从PHP拉取最新领地配置
|
||||
* ★ 领地数据即时同步:每15秒(±5)从PHP拉取最新领地配置
|
||||
* 配合60~90秒全量同步作为兜底
|
||||
*/
|
||||
private volatile boolean landSyncPulling = false;
|
||||
@@ -1688,8 +1690,8 @@ public class WebManager {
|
||||
landSyncFailCount++;
|
||||
}
|
||||
}
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(10), 20L * randomIntervalSeconds(10)); // 领地同步 10±10秒
|
||||
plugin.getLogger().info("[Web通信] 领地配置即时同步已启动(每10秒)");
|
||||
}.runTaskTimerAsynchronously(plugin, 20L * randomIntervalSeconds(15), 20L * randomIntervalSeconds(15)); // 领地同步 15±5秒
|
||||
plugin.getLogger().info("[Web通信] 领地配置即时同步已启动(每15秒±5)");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4847,7 +4849,7 @@ public class WebManager {
|
||||
// 启动注册请求轮询
|
||||
scheduleRegisterRequestPoll();
|
||||
|
||||
plugin.getLogger().info("[Web通信] Web注册请求轮询已启动(30~90秒随机间隔,静默运行)");
|
||||
plugin.getLogger().info("[Web通信] Web注册请求轮询已启动(12±4秒随机间隔,静默运行)");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4872,7 +4874,7 @@ public class WebManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
}.runTaskTimer(plugin, 20L * randomIntervalSeconds(3), 20L * randomIntervalSeconds(3)); // 注册轮询 3±10秒(最小1秒)
|
||||
}.runTaskTimer(plugin, 20L * randomIntervalSeconds(12), 20L * randomIntervalSeconds(12)); // 注册轮询 12±4秒
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user