fix: CLI/GUI交互优化 + 用户组PHP双向同步

1. CLI用户组列表:空列表时显示可点击创建链接,有列表时也显示创建入口
2. CLI公共建筑列表:每项显示可点击[传送到此]按钮,直接传送
3. GUI公共设施传送:改为打开GUI面板,点击建筑物品直接传送(非执行命令)
4. GUI管理员面板:新增用户组管理入口(slot31),显示组数量
5. Java pollAdminChanges:新增group_change类型处理,PHP变更后自动重载用户组
6. AreaProtection:补全Adventure API imports
This commit is contained in:
2026-06-28 00:15:44 +08:00
parent 8ef4744cbd
commit ae018f57e5
3 changed files with 129 additions and 5 deletions
+88 -3
View File
@@ -66,6 +66,7 @@ public class AreaGUIManager implements Listener {
*/ */
// ★ 管理员面板标题 // ★ 管理员面板标题
private static final String T_ADMIN_PANEL = "§6§l管理员配置面板"; private static final String T_ADMIN_PANEL = "§6§l管理员配置面板";
private static final String T_PUBLIC_BUILDING = "§b§l公共建筑传送";
public void openMainMenu(Player p) { public void openMainMenu(Player p) {
Inventory inv = Bukkit.createInventory(null, 54, T_MAIN); Inventory inv = Bukkit.createInventory(null, 54, T_MAIN);
@@ -798,9 +799,9 @@ public class AreaGUIManager implements Listener {
p.sendMessage("§cCLI管理器未初始化"); p.sendMessage("§cCLI管理器未初始化");
} }
} else if (raw == 41) { } else if (raw == 41) {
// ★ 公共设施传送 // ★ 公共设施传送 - 打开GUI直接传送
p.closeInventory(); event.setCancelled(true);
p.performCommand("protect listpublic"); openPublicBuildingList(p);
} else if (raw == 49) { } else if (raw == 49) {
plugin.getGui().openMain(p); plugin.getGui().openMain(p);
} }
@@ -1160,6 +1161,40 @@ public class AreaGUIManager implements Listener {
return; return;
} }
// ★ 公共建筑传送
if (T_PUBLIC_BUILDING.equals(title)) {
event.setCancelled(true);
if (raw == 49) {
openMainMenu(p);
return;
}
if (raw < 0 || raw >= 45) return;
// 获取公共建筑列表
java.util.List<AreaProtection.AreaConfig> publicLands = new ArrayList<>();
for (AreaProtection.AreaConfig ac : areaProtect.getAllLands().values()) {
if (ac.isPublicBuilding) publicLands.add(ac);
}
if (raw < publicLands.size()) {
AreaProtection.AreaConfig target = publicLands.get(raw);
p.closeInventory();
// 传送(优先传送点,否则领地中心)
org.bukkit.Location dest;
if (target.warpX != 0 || target.warpZ != 0 || target.warpY != 0) {
org.bukkit.World w = Bukkit.getWorld(target.warpWorld != null && !target.warpWorld.isEmpty() ? target.warpWorld : p.getWorld().getName());
if (w == null) w = p.getWorld();
dest = new org.bukkit.Location(w, target.warpX + 0.5, target.warpY, target.warpZ + 0.5, target.warpYaw, target.warpPitch);
} else {
dest = new org.bukkit.Location(p.getWorld(),
(target.x1 + target.x2) / 2.0 + 0.5,
p.getWorld().getHighestBlockYAt((target.x1 + target.x2) / 2, (target.z1 + target.z2) / 2) + 1,
(target.z1 + target.z2) / 2.0 + 0.5);
}
p.teleport(dest);
p.sendMessage("§a已传送至公共建筑: §f" + target.name);
}
return;
}
// 效果选择列表 // 效果选择列表
if (title.startsWith("§a§l选择效果 - ")) { if (title.startsWith("§a§l选择效果 - ")) {
event.setCancelled(true); event.setCancelled(true);
@@ -1336,6 +1371,15 @@ public class AreaGUIManager implements Listener {
"", "",
"§e左键+600 / 右键-600")); "§e左键+600 / 右键-600"));
// ★ 用户组管理(位置31)
UserGroupManager ugm = plugin.getUserGroup();
int groupCount = (ugm != null) ? ugm.getGroupConfigs().size() : 0;
inv.setItem(31, createItem(Material.PLAYER_HEAD, "§6§l用户组管理",
"§7当前: §f" + groupCount + " 个用户组",
"§7管理用户组的独立价格、上限和默认权限",
"",
"§e点击进入管理"));
// 返回按钮(位置48) // 返回按钮(位置48)
inv.setItem(48, createItem(Material.ARROW, "§c§l返回主菜单", "")); inv.setItem(48, createItem(Material.ARROW, "§c§l返回主菜单", ""));
@@ -1412,9 +1456,50 @@ public class AreaGUIManager implements Listener {
areaProtect.setPendingConfigInput(p.getUniqueId(), "peace_mode_max_duration"); areaProtect.setPendingConfigInput(p.getUniqueId(), "peace_mode_max_duration");
} else if (raw == 48) { } else if (raw == 48) {
openMainMenu(p); openMainMenu(p);
} else if (raw == 31) {
// ★ 用户组管理 - 打开CLI交互(GUI暂不支持复杂交互)
p.closeInventory();
p.performCommand("protect grouplist");
} }
} }
// ==================== 公共建筑传送 GUI ====================
/**
* 打开公共建筑列表,点击直接传送
*/
public void openPublicBuildingList(Player p) {
// 收集所有公共建筑
java.util.List<AreaProtection.AreaConfig> publicLands = new ArrayList<>();
for (AreaProtection.AreaConfig ac : areaProtect.getAllLands().values()) {
if (ac.isPublicBuilding) publicLands.add(ac);
}
Inventory inv = Bukkit.createInventory(null, 54, T_PUBLIC_BUILDING);
if (publicLands.isEmpty()) {
inv.setItem(22, createItem(Material.BARRIER, "§7暂无公共建筑设施",
"§7管理员可通过 /protect public <领地标记> 创建"));
} else {
int slot = 0;
for (AreaProtection.AreaConfig ac : publicLands) {
if (slot >= 45) break;
String warpInfo = (ac.warpX != 0 || ac.warpZ != 0) ? "§a有传送点" : "§7无传送点(将传送到领地中心)";
inv.setItem(slot, createItem(Material.BELL, "§b§l" + ac.name,
"§7所有者: §f" + ac.owner,
"§7传送: " + warpInfo,
"",
"§e点击传送到此公共建筑"));
slot++;
}
}
// 返回按钮
inv.setItem(49, createItem(Material.ARROW, "§c§l返回主菜单", ""));
p.openInventory(inv);
}
// ==================== 效果管理 GUI ==================== // ==================== 效果管理 GUI ====================
/** /**
+31 -2
View File
@@ -38,6 +38,10 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import java.util.Iterator; import java.util.Iterator;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import java.util.Set; import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
@@ -5841,10 +5845,15 @@ public class AreaProtection implements Listener {
int idx = 1; int idx = 1;
for (AreaConfig ac : publicLands) { for (AreaConfig ac : publicLands) {
String warpInfo = (ac.warpX != 0 || ac.warpZ != 0) ? "§a[有传送点]" : "§7[无传送点]"; String warpInfo = (ac.warpX != 0 || ac.warpZ != 0) ? "§a[有传送点]" : "§7[无传送点]";
sender.sendMessage("§e" + idx + ". §f" + ac.name + " §7所有者:" + ac.owner + " " + warpInfo); // 可点击传送的列表项
p.sendMessage(Component.empty()
.append(Component.text("§e" + idx + ". §f" + ac.name + " §7所有者:" + ac.owner + " " + warpInfo))
.append(Component.text(" §a[传送到此]"))
.hoverEvent(HoverEvent.showText(Component.text("§e点击传送到 " + ac.name)))
.clickEvent(ClickEvent.runCommand("/protect tpb " + ac.name))
);
idx++; idx++;
} }
sender.sendMessage("§7使用 /protect tpb <序号或名字> 传送");
return true; return true;
} }
if (sub.equals("tpb") || sub.equals("传送公共")) { if (sub.equals("tpb") || sub.equals("传送公共")) {
@@ -5898,6 +5907,17 @@ public class AreaProtection implements Listener {
Map<String, UserGroupManager.UserGroupConfig> groups = ugm.getGroupConfigs(); Map<String, UserGroupManager.UserGroupConfig> groups = ugm.getGroupConfigs();
if (groups.isEmpty()) { if (groups.isEmpty()) {
sender.sendMessage("§e暂无用户组定义"); sender.sendMessage("§e暂无用户组定义");
if (sender instanceof Player) {
Player pp = (Player) sender;
if (pp.hasPermission("sdf1.admin")) {
pp.sendMessage(Component.empty()
.append(Component.text("§a点击此处"))
.append(Component.text("§e创建第一个用户组"))
.hoverEvent(HoverEvent.showText(Component.text("§e点击开始交互式创建")))
.clickEvent(ClickEvent.suggestCommand("/protect groupset "))
);
}
}
} else { } else {
sender.sendMessage("§a§l=== 用户组列表 ==="); sender.sendMessage("§a§l=== 用户组列表 ===");
for (UserGroupManager.UserGroupConfig cfg : groups.values()) { for (UserGroupManager.UserGroupConfig cfg : groups.values()) {
@@ -5907,6 +5927,15 @@ public class AreaProtection implements Listener {
+ " §7(name=" + cfg.name + ", 优先级=" + cfg.priority + " §7(name=" + cfg.name + ", 优先级=" + cfg.priority
+ ", 价格=" + priceStr + ", 上限=" + maxStr + ")"); + ", 价格=" + priceStr + ", 上限=" + maxStr + ")");
} }
if (sender instanceof Player && ((Player) sender).hasPermission("sdf1.admin")) {
Player pp = (Player) sender;
pp.sendMessage(Component.empty()
.append(Component.text("§a点击此处"))
.append(Component.text("§e创建新用户组"))
.hoverEvent(HoverEvent.showText(Component.text("§e点击开始交互式创建")))
.clickEvent(ClickEvent.suggestCommand("/protect groupset "))
);
}
} }
return true; return true;
} }
+10
View File
@@ -3162,6 +3162,16 @@ public class WebManager {
} }
break; break;
} }
case "group_change": {
// ★ PHP端用户组变更 → 重新加载本地用户组配置
UserGroupManager ugm = plugin.getUserGroup();
if (ugm != null) {
ugm.loadGroupConfigs();
plugin.getLogger().info("[Web通信] PHP端用户组变更,已重新加载用户组配置");
applied = true;
}
break;
}
default: default:
plugin.getLogger().fine("[Web通信] 未知变更类型: " + changeType); plugin.getLogger().fine("[Web通信] 未知变更类型: " + changeType);
} }