修复异步打开GUI报错 + 创建领地快速创建

1. 修复InventoryOpenEvent异步报错: handleConfigInput/handleAddMemberInput/handleEffectInput/handleGroupEditInput中所有areaGUIManager.open调用改为Bukkit.getScheduler().runTask切主线程
2. 首页创建领地: 无选点时自动以玩家为中心3×3快速创建领地,自动命名+冲突数字0~999
3. AreaProtection新增quickCreateLand/hasPos1/hasPos2方法
This commit is contained in:
2026-06-29 15:48:31 +08:00
parent c94fb60a86
commit fa9be74e1f
2 changed files with 135 additions and 11 deletions
+7 -1
View File
@@ -813,9 +813,15 @@ public class AreaGUIManager implements Listener {
p.closeInventory(); p.closeInventory();
giveWandTool(p); giveWandTool(p);
} else if (raw == 12) { } else if (raw == 12) {
// 创建领地 - 给予选择工具 // ★ 创建领地 - 无选点则快速创建(自身3×3),有选点则给工具
p.closeInventory(); p.closeInventory();
boolean hasPos = areaProtect.hasPos1(p.getUniqueId()) && areaProtect.hasPos2(p.getUniqueId());
if (hasPos) {
p.performCommand("protect 工具"); p.performCommand("protect 工具");
} else {
// 快速创建:以自身为中心3×3
areaProtect.quickCreateLand(p);
}
} else if (raw == 14) { } else if (raw == 14) {
openLandList(p, 0); openLandList(p, 0);
} else if (raw == 22) { } else if (raw == 22) {
+127 -9
View File
@@ -121,6 +121,9 @@ public class AreaProtection implements Listener {
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
private final Set<UUID> selecting = private final Set<UUID> selecting =
ConcurrentHashMap.newKeySet(); ConcurrentHashMap.newKeySet();
public boolean hasPos1(UUID uuid) { return pos1.containsKey(uuid); }
public boolean hasPos2(UUID uuid) { return pos2.containsKey(uuid); }
public boolean denyRaid = false; public boolean denyRaid = false;
// ===== 统一文件夹 ===== // ===== 统一文件夹 =====
private final File rootDir; private final File rootDir;
@@ -8140,9 +8143,11 @@ public class AreaProtection implements Listener {
String configName = getConfigNameByKey(configKey); String configName = getConfigNameByKey(configKey);
p.sendMessage("§a§l[配置] §f" + configName + " 已更新: §e" + currentValue + " → " + newValue); p.sendMessage("§a§l[配置] §f" + configName + " 已更新: §e" + currentValue + " → " + newValue);
// 刷新GUI // 刷新GUI(必须切主线程:handleConfigInput来自AsyncPlayerChatEvent)
if (plugin.areaGUIManager != null) { if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openAdminPanel(p); Sdf1_login.Main pl = plugin;
org.bukkit.entity.Player pp = p;
org.bukkit.Bukkit.getScheduler().runTask(pl, () -> pl.areaGUIManager.openAdminPanel(pp));
} }
return true; return true;
} }
@@ -8195,9 +8200,12 @@ public class AreaProtection implements Listener {
addLandMember(landName, playerName); addLandMember(landName, playerName);
p.sendMessage("§a§l[添加成员] §f已成功添加 " + playerName + " 为领地成员"); p.sendMessage("§a§l[添加成员] §f已成功添加 " + playerName + " 为领地成员");
// 刷新GUI // 刷新GUI(必须切主线程)
if (plugin.areaGUIManager != null) { if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openAddMember(p, landName); Sdf1_login.Main pl = plugin;
org.bukkit.entity.Player pp = p;
String ln = landName;
org.bukkit.Bukkit.getScheduler().runTask(pl, () -> pl.areaGUIManager.openAddMember(pp, ln));
} }
return true; return true;
} }
@@ -8351,9 +8359,13 @@ public class AreaProtection implements Listener {
if (plugin.areaCLIManager != null) plugin.areaCLIManager.showEffectsManagement(p, landName, 3); if (plugin.areaCLIManager != null) plugin.areaCLIManager.showEffectsManagement(p, landName, 3);
} }
// 刷新GUI,回到原来的subPage // 刷新GUI,回到原来的subPage(必须切主线程)
if (plugin.areaGUIManager != null) { if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openEffectsManagement(p, landName, subPage); Sdf1_login.Main pl = plugin;
org.bukkit.entity.Player pp = p;
String ln = landName;
int sp = subPage;
org.bukkit.Bukkit.getScheduler().runTask(pl, () -> pl.areaGUIManager.openEffectsManagement(pp, ln, sp));
} }
return true; return true;
} }
@@ -8446,7 +8458,10 @@ public class AreaProtection implements Listener {
if (message.trim().equalsIgnoreCase("取消")) { if (message.trim().equalsIgnoreCase("取消")) {
p.sendMessage("§7已取消编辑"); p.sendMessage("§7已取消编辑");
if (plugin.areaGUIManager != null) { if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openGroupEditPanel(p, groupName); Sdf1_login.Main pl = plugin;
org.bukkit.entity.Player pp = p;
String gn = groupName;
org.bukkit.Bukkit.getScheduler().runTask(pl, () -> pl.areaGUIManager.openGroupEditPanel(pp, gn));
} }
return true; return true;
} }
@@ -8509,9 +8524,12 @@ public class AreaProtection implements Listener {
ugm.updateGroupConfig(cfg); ugm.updateGroupConfig(cfg);
p.sendMessage("§a已将用户组 §e" + cfg.displayName + " §a的 §f" + fieldLabel + " §a修改为 §e" + parsed); p.sendMessage("§a已将用户组 §e" + cfg.displayName + " §a的 §f" + fieldLabel + " §a修改为 §e" + parsed);
// 刷新GUI // 刷新GUI(必须切主线程)
if (plugin.areaGUIManager != null) { if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openGroupEditPanel(p, groupName); Sdf1_login.Main pl = plugin;
org.bukkit.entity.Player pp = p;
String gn = groupName;
org.bukkit.Bukkit.getScheduler().runTask(pl, () -> pl.areaGUIManager.openGroupEditPanel(pp, gn));
} }
return true; return true;
} }
@@ -9795,4 +9813,104 @@ public class AreaProtection implements Listener {
return c; return c;
} }
} }
// ==================== 快速创建领地(无选点,以自身为中心) ====================
/**
* ★ 快速创建领地:以玩家为中心3×3,自动命名+冲突数字0~999
* @return true成功创建,false失败
*/
public boolean quickCreateLand(Player p) {
if (p == null || dbConnection == null) return false;
// ★ 检查领地上限
UserGroupManager ugm = plugin.getUserGroup();
int maxLands = (ugm != null) ? ugm.getPlayerMaxLands(p.getName(), globalMaxLandsPerPlayer) : globalMaxLandsPerPlayer;
long landCount = areas.values().stream().filter(a -> p.getName().equalsIgnoreCase(a.owner)).count();
// DB兜底
if (landCount < maxLands) {
try {
java.sql.PreparedStatement cs = dbConnection.prepareStatement("SELECT COUNT(*) as cnt FROM area_lands WHERE LOWER(owner) = LOWER(?)");
cs.setString(1, p.getName());
java.sql.ResultSet cr = cs.executeQuery();
if (cr.next()) { long dbc = cr.getLong("cnt"); if (dbc > landCount) landCount = dbc; }
cr.close(); cs.close();
} catch (Exception ignored) {}
}
if (landCount >= maxLands) {
p.sendMessage("§c§l[防护] §f已达领地上限!每人最多 §e" + maxLands + " §f个领地");
return false;
}
// ★ 以玩家为中心3×3
int cx = p.getLocation().getBlockX();
int cz = p.getLocation().getBlockZ();
int x1 = cx - 1, z1 = cz - 1;
int x2 = cx + 1, z2 = cz + 1;
int area = 9; // 3×3
// ★ 检查这个区域是否与其他领地重叠
for (AreaConfig other : areas.values()) {
if (!other.world.equalsIgnoreCase(p.getWorld().getName())) continue;
// AABB重叠检测
if (x1 <= other.x2 && x2 >= other.x1 && z1 <= other.z2 && z2 >= other.z1) {
p.sendMessage("§c§l[防护] §f该区域与领地 §e" + other.name + " §f重叠,请走远点再试");
return false;
}
}
// ★ 计算费用
UserGroupManager ug = plugin.getUserGroup();
int pricePerSqm = (ug != null) ? ug.getPlayerLandPricePerSqm(p.getName(), globalCreatePricePerSqm) : globalCreatePricePerSqm;
int totalCost = area * pricePerSqm;
// ★ 检查余额
BondManager bm = plugin.getBonds();
if (bm != null && totalCost > 0) {
int bal = bm.getBonds(p.getName());
if (bal < totalCost) {
p.sendMessage("§c§l[防护] §f余额不足!需要 §e" + totalCost + " §f债券,当前 §a" + bal);
return false;
}
}
// ★ 自动命名:玩家名,冲突加数字0~999
String autoName = p.getName();
if (areas.containsKey(autoName)) {
boolean found = false;
for (int i = 0; i <= 999; i++) {
String candidate = p.getName() + i;
if (!areas.containsKey(candidate)) { autoName = candidate; found = true; break; }
}
if (!found) {
p.sendMessage("§c§l[防护] §f无法找到可用的领地名(已用尽0~999后缀)");
return false;
}
}
// ★ 扣费
if (bm != null && totalCost > 0) {
String src = (pricePerSqm != globalCreatePricePerSqm) ? "(用户组优惠价)" : "";
if (!bm.deductBonds(p.getName(), totalCost, "land_create", p.getName(), p.getName(),
"快速创建领地: " + autoName + " (" + area + "㎡×" + pricePerSqm + ")")) {
p.sendMessage("§c§l[防护] §f扣费失败,请稍后重试");
return false;
}
p.sendMessage("§a§l[防护] §f创建领地扣除 §e" + totalCost + " §f债券(" + area + "㎡×" + pricePerSqm + "/㎡)" + src);
}
// ★ 创建领地
AreaConfig ac = new AreaConfig();
ac.name = autoName;
ac.owner = p.getName();
ac.world = p.getWorld().getName();
ac.x1 = x1; ac.z1 = z1; ac.x2 = x2; ac.z2 = z2;
ac.yMin = 0; ac.yMax = 255;
saveAreaToDb(ac);
areas.put(autoName, ac);
loadAllAreas();
p.sendMessage("§a§l[防护] §f区域 §e" + autoName + " §f已创建(" + area + "㎡,以你为中心3×3)");
return true;
}
} }