添加改主心跳延时机制: PHP前端轮询1分钟,Java回调通知原主人,支持撤回

This commit is contained in:
2026-06-29 20:06:17 +08:00
parent fe4bee53de
commit bbbbf54b3f
2 changed files with 124 additions and 2 deletions
+82 -1
View File
@@ -5064,7 +5064,7 @@ public class AreaProtection implements Listener {
"info", "setowner", "addvisitor", "removevisitor",
"listvisitors", "transfer", "shop",
"menu", "菜单", "sdf1debug", "testclear", "cli",
"取消删除", "canceldelete",
"取消删除", "canceldelete", "canceladminchange",
"removemember", "addmember",
"config", "配置",
"public", "公共", "listpublic", "公共列表", "tpb", "传送公共",
@@ -6612,6 +6612,87 @@ public class AreaProtection implements Listener {
return true;
}
// ===== 取消管理员改主 =====
if (sub.equals("canceladminchange")) {
if (!(sender instanceof Player)) {
sender.sendMessage("§c仅玩家可用");
return true;
}
Player p = (Player) sender;
if (args.length < 2) {
sender.sendMessage("§e用法: /protect canceladminchange <领地名>");
return true;
}
String areaName = args[1];
String resolved = resolveAreaName(areaName);
if (resolved != null) areaName = resolved;
// 检查领地是否存在
AreaConfig ac = getLand(areaName);
if (ac == null) {
sender.sendMessage("§c领地不存在: " + areaName);
return true;
}
// 检查是否是原主人
if (!p.getName().equalsIgnoreCase(ac.owner)) {
sender.sendMessage("§c只有原主人才能撤回改主");
return true;
}
// 查找最近的管理员改主记录
try {
if (dbConnection == null) {
sender.sendMessage("§c数据库未连接");
return true;
}
PreparedStatement ps = dbConnection.prepareStatement(
"SELECT id, change_data FROM web_admin_changes WHERE change_type = 'owner_change' AND target_name = ? AND status = 'completed' ORDER BY id DESC LIMIT 1");
ps.setString(1, areaName);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int changeId = rs.getInt("id");
String changeDataStr = rs.getString("change_data");
java.util.Map<String, Object> changeData = WebManager.parseJson(changeDataStr);
String newOwner = (String) changeData.get("new_owner");
String oldOwner = (String) changeData.get("old_owner");
// 验证当前owner是否是newOwner(即已经被改主了)
if (!p.getName().equalsIgnoreCase(newOwner)) {
sender.sendMessage("§c当前所有者不是你,无法撤回");
rs.close();
ps.close();
return true;
}
// 回退owner
PreparedStatement updatePs = dbConnection.prepareStatement(
"UPDATE area_lands SET owner = ? WHERE name = ?");
updatePs.setString(1, oldOwner);
updatePs.setString(2, areaName);
updatePs.executeUpdate();
updatePs.close();
// 更新内存
ac.owner = oldOwner;
// 通知PHP回滚
plugin.webManager.callbackOwnerChangeToPHP(changeId, false, "原主人撤回");
sender.sendMessage("§a§l[防护] §f已撤回领地 §e" + areaName + " §f的改主,恢复为 §a" + oldOwner);
plugin.getLogger().info("[防护] " + p.getName() + " 撤回了领地 " + areaName + " 的管理员改主");
} else {
sender.sendMessage("§c没有可撤回的改主记录");
}
rs.close();
ps.close();
} catch (Exception e) {
sender.sendMessage("§c撤回失败: " + e.getMessage());
plugin.getLogger().warning("[防护] 撤回管理员改主失败: " + e.getMessage());
}
return true;
}
// ===== add 加白名单 =====
if (sub.equals("add")) {
if (args.length == 2) {
+42 -1
View File
@@ -2251,6 +2251,31 @@ public class WebManager {
String resp = doPost(webBaseUrl + "/api/sync.php?action=receive_token", jsonBody);
if (resp != null) {
plugin.getLogger().info("[Web通信] Token注册成功");
plugin.getLogger().warning("\n" +
" __ __ _ _ \n" +
" \\ \\ / / | | | | \n" +
" \\ \\ /\\ / /__ ___| |__ ___ _ __ ___ ___ | |_ ___ \n" +
" \\ \\/ \\/ / _ \\/ __| '_ \\ / _ \\| '_ ` _ \\ / _ \\ | __/ _ \\ \n" +
" \\ /\\ / __/ (__| | | | (_) | | | | | | __/ | || (_) | \n" +
" \\/ \\/ \\___|\\___|_| |_|\\___/|_| |_| |_|\\___| \\__\\___/ _ \n" +
" | | (_) \n" +
" ___ __ _ ___ _ _ _ _ __ _ _ __ | |_ __ _ _ __ __ ___ __ _ _ __ ___ ___ _ ____ _____ _ __ \n" +
" / __/ _` |/ _ \\ | | | | | | |/ _` | '_ \\ | __/ _` | '_ \\ \\ \\/ / |/ _` | '_ \\ / __|/ _ \\ '__\\ \\ / / _ \\ '__| \n" +
" | (_| (_| | (_) | | |_| | |_| | (_| | | | | | || (_| | | | | > <| | (_| | | | | \\__ \\ __/ | \\ V / __/ | \n" +
" \\___\\__,_|\\___/ \\__, |\\__,_|\\__,_|_| |_| \\__\\__,_|_| |_| /_/\\_\\_|\\__,_|_| |_| |___/\\___|_| \\_/ \\___|_| \n" +
" __/ | _____ _____ ___ _ _ _ _ __ \n" +
" |___/ |_ _| __ \\ _ |__ \\ | | (_) | (_)/ _| \n" +
" ___ ___ _ ____ _____ _ __| | | |__) (_) _ __ ___ ___ ) | _ _ _ __ ___| |__ _ __| |_| |_ _ _ ___ _ __ \n" +
" / __|/ _ \\ '__\\ \\ / / _ \\ '__| | | ___/ | '_ ` _ \\ / __| / / | | | | '_ \\/ __| '_ \\| |/ _` | | _| | | | / __| '_ \\ \n" +
" \\__ \\ __/ | \\ V / __/ | _| |_| | _ | | | | | | (__ / /_ | |_| | |_) \\__ \\ | | | | (_| | | | | |_| || (__| | | |\n" +
" |___/\\___|_| \\_/ \\___|_||_____|_| _(_)_|_| |_| |_|\\___|____(_)__, | .__/|___/_| |_|_|\\__,_|_|_| \\__,_(_)___|_| |_|\n" +
" | | _ |___ \\ / _ \\ / /____ / _ \\ __/ | | \n" +
" _ __ ___ ___| |_(_) __) | | | |/ /_ / / (_) | |___/|_| \n" +
" | '_ \\ / _ \\/ __| __| |__ <| | | | '_ \\ / / \\__, | \n" +
" | |_) | (_) \\__ \\ |_ _ ___) | |_| | (_) / / / / \n" +
" | .__/ \\___/|___/\\__(_) |____/ \\___/ \\___/_/ /_/ \n" +
" | | \n" +
" |_| ");
}
} catch (Exception e) {
plugin.getLogger().warning("[Web通信] Token注册失败: " + e.getClass().getSimpleName() + " - " + e.getMessage());
@@ -3513,6 +3538,22 @@ public class WebManager {
plugin.getLogger().info("[Web通信] PHP端领地所有者变更: " + landName + " → " + newOwner);
// 3. 回调PHP更新本地副本
callbackOwnerChangeToPHP(id, true, "");
// 4. 通知原主人(带撤回超链接)
String oldOwner = String.valueOf(changeData.getOrDefault("old_owner", ""));
if (!oldOwner.isEmpty()) {
org.bukkit.entity.Player oldOwnerPlayer = Bukkit.getPlayerExact(oldOwner);
if (oldOwnerPlayer != null && oldOwnerPlayer.isOnline()) {
net.kyori.adventure.text.Component msg = net.kyori.adventure.text.Component.empty()
.append(net.kyori.adventure.text.Component.text("§c§l[系统] §f§l你的领地 §e" + landName + " §f已被管理员变更为 §a" + newOwner))
.append(net.kyori.adventure.text.Component.text(" "))
.append(net.kyori.adventure.text.Component.text("§c§l[撤回]")
.hoverEvent(net.kyori.adventure.text.event.HoverEvent.showText(
net.kyori.adventure.text.Component.text("§e点击撤回此次改主")))
.clickEvent(net.kyori.adventure.text.event.ClickEvent.runCommand("/protect canceladminchange " + landName)));
oldOwnerPlayer.sendMessage(msg);
plugin.getLogger().info("[Web通信] 已通知原主人 " + oldOwner + " 关于领地 " + landName + " 的改主");
}
}
applied = true;
}
break;
@@ -3683,7 +3724,7 @@ public class WebManager {
/**
* ★ 回调PHP:管理面板改主执行结果
*/
private void callbackOwnerChangeToPHP(int changeId, boolean success, String reason) {
public void callbackOwnerChangeToPHP(int changeId, boolean success, String reason) {
try {
String url = webBaseUrl + "/api/land_api.php?action=owner_change_callback&secret=" + java.net.URLEncoder.encode(secretKey, "UTF-8")
+ "&change_id=" + changeId