fix: 领地系统多项修复 - 管理员TAG验证/和平模式/袭击模式命名/效果管理GUI/添加成员功能

This commit is contained in:
2026-06-24 18:32:25 +08:00
parent 7ae4f46f75
commit bbf23aad31
4 changed files with 271 additions and 25 deletions
+6 -6
View File
@@ -538,7 +538,7 @@ public class AreaCLIManager {
String permName = getPermNameByKey(permKey);
boolean newState = !oldState;
// ★ newState是deny值:true=禁止,false=允许
p.sendMessage("§a已切换 §e" + permName + " §7→ " + (!newState ? "§a已允许" : "§c已禁止"));
p.sendMessage("§a已切换 §e" + permName + " §7→ " + (newState ? "§a已启用" : "§c已关闭"));
}
/**
@@ -615,7 +615,7 @@ public class AreaCLIManager {
perms.add(new PermItem("mount", "骑乘坐具", !land.denyMount));
perms.add(new PermItem("ender_pearl", "投掷末影珍珠", !land.denyEnderPearl));
perms.add(new PermItem("thrown_projectiles", "投掷物(三叉戟/雪球/风蛋)", !land.denyThrownProjectiles));
perms.add(new PermItem("raid", "禁止袭击", !land.denyRaid));
perms.add(new PermItem("raid", "启用袭击", !land.denyRaid));
perms.add(new PermItem("bow", "弓箭射击", !land.denyBow));
perms.add(new PermItem("potion", "药水效果", !land.denyPotion));
perms.add(new PermItem("fire", "点燃", !land.denyFire));
@@ -636,7 +636,7 @@ public class AreaCLIManager {
perms.add(new PermItem("wool_shear", "剪切羊毛/生物", !land.denyWoolShear));
perms.add(new PermItem("animal_feed", "投喂动物", !land.denyAnimalFeeding));
perms.add(new PermItem("glowing", "玩家发光", !land.denyGlowing));
perms.add(new PermItem("peace_mode", "禁止和平模式", !land.peaceMode));
perms.add(new PermItem("peace_mode", "启用和平模式", land.peaceMode));
return perms;
}
@@ -649,7 +649,7 @@ public class AreaCLIManager {
case "mount": return "骑乘坐具";
case "ender_pearl": return "投掷末影珍珠";
case "thrown_projectiles": return "投掷物";
case "raid": return "禁止袭击";
case "raid": return "启用袭击";
case "bow": return "弓箭射击";
case "potion": return "药水效果";
case "fire": return "点燃";
@@ -670,7 +670,7 @@ public class AreaCLIManager {
case "wool_shear": return "剪切羊毛";
case "animal_feed": return "投喂动物";
case "glowing": return "玩家发光";
case "peace_mode": return "禁止和平模式";
case "peace_mode": return "启用和平模式";
default: return key;
}
}
@@ -966,7 +966,7 @@ public class AreaCLIManager {
{"wool_shear", "剪切羊毛/生物", "denyWoolShear"},
{"animal_feed", "投喂动物", "denyAnimalFeeding"},
{"glowing", "玩家发光", "denyGlowing"},
{"peace_mode", "禁止和平模式", "peaceMode"}
{"peace_mode", "启用和平模式", "peaceMode"}
};
for (String[] def : permDefs) {
+124 -3
View File
@@ -34,6 +34,9 @@ public class AreaGUIManager implements Listener {
private static final String T_LAND_SETTINGS = "§6§l领地设置";
private static final String T_MEMBER_PERM_LIST = "§6§l成员权限列表";
private static final String T_PLAYER_PERM = "§6§l成员权限";
private static final String T_EFFECTS_MGMT = "§b§l效果管理";
private static final String T_EFFECTS_CLEAR = "§b§l单清效果";
private static final String T_EFFECTS_GIVE = "§b§l增益效果";
// 每页显示数量
private static final int PAGE_SIZE = 45;
@@ -49,6 +52,9 @@ public class AreaGUIManager implements Listener {
// ★ 玩家当前编辑的per-player目标玩家
private final Map<UUID, String> playerPermTarget = new HashMap<>();
// ★ 效果管理待处理输入:UUID → [landName, inputType]
private final Map<UUID, String[]> pendingEffectInput = new HashMap<>();
public AreaGUIManager(Main plugin, AreaProtection areaProtect) {
this.plugin = plugin;
this.areaProtect = areaProtect;
@@ -497,7 +503,7 @@ public class AreaGUIManager implements Listener {
}
/**
* 打开添加成员菜单
* 打开添加成员菜单 - 显示在线玩家 + 自定义输入
*/
public void openAddMember(Player p, String landName) {
managingLand.put(p.getUniqueId(), landName);
@@ -524,6 +530,11 @@ public class AreaGUIManager implements Listener {
slot++;
}
// 自定义输入成员(位置45)
inv.setItem(45, createItem(Material.PAPER, "§e§l自定义输入成员",
"§7点击后在聊天栏输入玩家名",
"§7将添加到该领地"));
// 返回按钮(位置48)
inv.setItem(48, createItem(Material.ARROW, "§c§l返回成员列表", ""));
@@ -903,6 +914,21 @@ public class AreaGUIManager implements Listener {
return;
}
// 效果管理
if (title.startsWith("§b§l效果管理") || title.startsWith("§b§l单清效果") || title.startsWith("§b§l增益效果")) {
event.setCancelled(true);
String landName = managingLand.get(p.getUniqueId());
if (landName == null) return;
// 从标题提取subPage
int subPage = 1;
if (title.contains("单清效果")) subPage = 2;
else if (title.contains("增益效果")) subPage = 3;
handleEffectsManagementClick(p, raw, subPage, landName);
return;
}
// 添加成员
if (title.startsWith(T_ADD_MEMBER)) {
event.setCancelled(true);
@@ -921,6 +947,11 @@ public class AreaGUIManager implements Listener {
openAddMember(p, landName);
}
}
} else if (raw == 45) {
// 自定义输入成员:打开聊天栏等待玩家名
p.closeInventory();
p.sendMessage("§e§l[添加成员] §f请输入要添加的玩家名:");
areaProtect.setPendingAddMemberInput(p.getUniqueId(), landName);
} else if (raw == 48) {
openMemberList(p, landName, 0);
}
@@ -1006,7 +1037,7 @@ public class AreaGUIManager implements Listener {
// 和平模式(位置13)
Material peaceMat = land.peaceMode ? Material.LIME_DYE : Material.GRAY_DYE;
inv.setItem(13, createItem(peaceMat, "§e§l和平模式",
"§7当前状态: " + (land.peaceMode ? "§a已启用" : "§c已禁用"),
"§7当前状态: " + (land.peaceMode ? "§a已启用" : "§c已关闭"),
"§7新生物进入领地后有保护期",
"",
"§e点击切换"));
@@ -1162,7 +1193,7 @@ public class AreaGUIManager implements Listener {
/**
* 打开效果管理菜单
*/
private void openEffectsManagement(Player p, String landName, int subPage) {
public void openEffectsManagement(Player p, String landName, int subPage) {
managingLand.put(p.getUniqueId(), landName);
AreaProtection.AreaConfig land = areaProtect.getLand(landName);
@@ -1234,6 +1265,32 @@ public class AreaGUIManager implements Listener {
p.openInventory(inv);
}
// ========== 子菜单3:增益效果列表 ==========
else if (subPage == 3) {
Inventory inv = Bukkit.createInventory(null, 54, "§b§l增益效果 - " + landName);
if (land.giveEffects.isEmpty()) {
inv.setItem(22, createItem(Material.BARRIER, "§7§l暂无增益效果",
"§7使用快捷指令添加: /protect cli effectsaddadd <效果名> [等级] [秒数]",
"",
"§e示例: /protect cli effectsaddadd 力量 2 300"));
} else {
for (int i = 0; i < Math.min(land.giveEffects.size(), 36); i++) {
String[] eff = land.giveEffects.get(i);
String desc = eff[0] + (eff.length > 1 ? " Lv" + eff[1] : "") + (eff.length > 2 ? " " + eff[2] + "秒" : "");
inv.setItem(i, createItem(Material.GOLDEN_CARROT, "§a" + desc,
"§7点击移除此增益效果",
"§e序号: " + (i + 1)));
}
}
inv.setItem(48, createItem(Material.ARROW, "§c§l返回效果管理", ""));
inv.setItem(53, createItem(Material.BOOK, "§a§l添加效果",
"§7点击后在聊天栏输入效果名(如:缓慢、中毒)"));
p.openInventory(inv);
}
// ========== 子菜单3:增益效果列表 ==========
else if (subPage == 3) {
Inventory inv = Bukkit.createInventory(null, 54, "§b§l增益效果 - " + landName);
@@ -1260,4 +1317,68 @@ public class AreaGUIManager implements Listener {
p.openInventory(inv);
}
}
/**
* 处理效果管理GUI点击事件
*/
private void handleEffectsManagementClick(Player p, int raw, int subPage, String landName) {
AreaProtection.AreaConfig land = areaProtect.getLand(landName);
if (land == null) return;
// 子菜单1:开关管理
if (subPage == 1) {
if (raw == 11) {
// 切换清除所有负面效果
land.clearAllBadEffects = !land.clearAllBadEffects;
areaProtect.saveAreaToDb(land);
openEffectsManagement(p, landName, 1);
} else if (raw == 13) {
// 切换禁止所有效果
land.denyAllEffects = !land.denyAllEffects;
areaProtect.saveAreaToDb(land);
openEffectsManagement(p, landName, 1);
} else if (raw == 15) {
// 打开单清效果列表
openEffectsManagement(p, landName, 2);
} else if (raw == 17) {
// 打开增益效果列表
openEffectsManagement(p, landName, 3);
} else if (raw == 48) {
// 返回管理领地
openLandManage(p, landName);
}
}
// 子菜单2:单清效果列表
else if (subPage == 2) {
if (raw < land.clearEffects.size()) {
// 移除单清效果
land.clearEffects.remove(raw);
areaProtect.saveAreaToDb(land);
openEffectsManagement(p, landName, 2);
} else if (raw == 48) {
openEffectsManagement(p, landName, 1);
} else if (raw == 53) {
// 打开聊天栏输入效果名
p.closeInventory();
p.sendMessage("§e§l[添加清除效果] §f请输入效果名(如:缓慢、中毒、凋零):");
areaProtect.setPendingClearEffectInput(p.getUniqueId(), landName, "clear");
}
}
// 子菜单3:增益效果列表
else if (subPage == 3) {
if (raw < land.giveEffects.size()) {
// 移除增益效果
land.giveEffects.remove(raw);
areaProtect.saveAreaToDb(land);
openEffectsManagement(p, landName, 3);
} else if (raw == 48) {
openEffectsManagement(p, landName, 1);
} else if (raw == 53) {
// 打开聊天栏输入增益效果
p.closeInventory();
p.sendMessage("§e§l[添加增益效果] §f请输入: 效果名 [等级] [秒数] (例: 力量 2 300)");
areaProtect.setPendingClearEffectInput(p.getUniqueId(), landName, "give");
}
}
}
}
+129 -16
View File
@@ -94,6 +94,10 @@ public class AreaProtection implements Listener {
final Map<java.util.UUID, Long> wandCooldownMap = new ConcurrentHashMap<>();
// ★ 管理员配置输入等待:UUID → 配置key(GUI点击后等待玩家聊天输入)
private final Map<java.util.UUID, String> pendingConfigInput = new ConcurrentHashMap<>();
// ★ 添加成员输入等待:UUID → 领地名
private final Map<java.util.UUID, String> pendingAddMemberInput = new ConcurrentHashMap<>();
// ★ 效果管理待处理输入:UUID → [landName, inputType]
private final Map<java.util.UUID, String[]> pendingEffectInput = new ConcurrentHashMap<>();
// ★ 全局配置默认值
private int globalCreatePricePerSqm = 10; // 每㎡创建价格
@@ -2446,26 +2450,20 @@ public class AreaProtection implements Listener {
/**
* 检查玩家是否为区域防护管理员
* 支持TAG和OP两种模式(不共存,按配置文件中的顺序优先)
* 全局管理员不受访客权限限制
* 与 Main.isAdmin() 使用相同的 ScoreboardTag 机制
*/
public boolean isAreaAdmin(Player player) {
ConfigManager cfg = plugin.getConfigMgr();
if (cfg == null) return player.isOp();
if (cfg == null) return false;
String mode = cfg.areaProtectAdminMode;
if ("op".equals(mode)) {
// OP模式:只有OP是管理员
return player.isOp();
} else {
// TAG模式(默认):有指定Tag的玩家是管理员
String tag = cfg.areaProtectAdminTag;
if (tag == null || tag.isEmpty()) return player.isOp();
String playerName = player.getName();
// 检查玩家是否拥有该权限节点(作为Tag的替代方案)
// 如果没有权限系统,直接检查名字是否匹配
return player.hasPermission("area.admin")
|| player.isOp(); // OP始终是管理员(fallback)
String tag = cfg.areaProtectAdminTag;
if (tag == null || tag.isEmpty()) return false;
// 使用ScoreboardTag验证(与Main.isAdmin()一致)
try {
return player.getScoreboardTags().contains(tag);
} catch (Exception e) {
return false;
}
}
@@ -7040,6 +7038,121 @@ public class AreaProtection implements Listener {
return true;
}
/**
* 设置等待添加成员输入状态
*/
public void setPendingAddMemberInput(java.util.UUID uuid, String landName) {
pendingAddMemberInput.put(uuid, landName);
}
/**
* 检查并处理添加成员输入
* @return true 如果是添加成员输入,已处理
*/
public boolean handleAddMemberInput(Player p, String message) {
String landName = pendingAddMemberInput.remove(p.getUniqueId());
if (landName == null) return false;
String playerName = message.trim();
// 验证玩家名格式
if (!playerName.matches("^[a-zA-Z0-9_]{3,16}$")) {
p.sendMessage("§c§l[添加成员] §f无效的玩家名格式(3-16位字母数字下划线): " + playerName);
p.sendMessage("§7请重新输入有效玩家名,或输入 cancel 取消");
return true;
}
// 检查玩家是否已存在(本地)
Player target = Bukkit.getPlayerExact(playerName);
if (target == null) {
// 玩家不在线,但仍然可以添加(因为可能在数据库中有记录)
p.sendMessage("§e§l[添加成员] §f玩家 " + playerName + " 当前不在线,但仍可添加为成员");
}
// 检查是否已是成员
Set<String> members = getLandMembers(landName);
if (members.contains(playerName)) {
p.sendMessage("§c§l[添加成员] §f" + playerName + " 已经是该领地成员");
return true;
}
// 添加成员
addLandMember(landName, playerName);
p.sendMessage("§a§l[添加成员] §f已成功添加 " + playerName + " 为领地成员");
// 刷新GUI
if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openAddMember(p, landName);
}
return true;
}
/**
* 设置等待效果管理输入状态
*/
public void setPendingClearEffectInput(java.util.UUID uuid, String landName, String inputType) {
pendingEffectInput.put(uuid, new String[]{landName, inputType});
}
/**
* 检查并处理效果管理输入
* @return true 如果是效果管理输入,已处理
*/
public boolean handleEffectInput(Player p, String message) {
String[] landAndType = pendingEffectInput.remove(p.getUniqueId());
if (landAndType == null) return false;
String landName = landAndType[0];
String inputType = landAndType[1];
AreaProtection.AreaConfig land = getLand(landName);
if (land == null) {
p.sendMessage("§c领地不存在");
return true;
}
if ("clear".equals(inputType)) {
// 添加单清效果
String effName = message.trim();
if (effName.isEmpty()) {
p.sendMessage("§c§l[添加清除效果] §f效果名不能为空");
return true;
}
if (!land.clearEffects.contains(effName)) {
land.clearEffects.add(effName);
saveAreaToDb(land);
p.sendMessage("§a§l[添加清除效果] §f已添加: " + effName);
} else {
p.sendMessage("§e§l[添加清除效果] §f效果 " + effName + " 已在列表中");
}
} else if ("give".equals(inputType)) {
// 添加增益效果: 格式 效果名 [等级] [秒数]
String[] parts = message.trim().split("\\s+");
if (parts.length < 1) {
p.sendMessage("§c§l[添加增益效果] §f请输入: 效果名 [等级] [秒数]");
return true;
}
String effName = parts[0].trim();
int effLv = 1;
int effDur = 300; // 默认5分钟
try {
if (parts.length >= 2) effLv = Integer.parseInt(parts[1]);
if (parts.length >= 3) effDur = Integer.parseInt(parts[2]);
} catch (NumberFormatException ignored) {
p.sendMessage("§c等级和秒数必须是数字");
return true;
}
String[] effRecord = {effName, String.valueOf(effLv), String.valueOf(effDur)};
land.giveEffects.add(effRecord);
saveAreaToDb(land);
p.sendMessage("§a§l[添加增益效果] §f已添加: " + effName + " Lv" + effLv + " " + effDur + "秒");
}
// 刷新GUI
if (plugin.areaGUIManager != null) {
plugin.areaGUIManager.openEffectsManagement(p, landName, 1);
}
return true;
}
private String getConfigNameByKey(String key) {
switch (key) {
case "create_price_per_sqm": return "创建价格(每㎡)";
+12
View File
@@ -2535,6 +2535,18 @@ public class Main extends JavaPlugin
return;
}
// ★ 添加成员输入拦截(GUI点击后聊天栏输入玩家名)
if (areaProtection != null && areaProtection.handleAddMemberInput(p, msg)) {
e.setCancelled(true);
return;
}
// ★ 效果管理输入拦截(GUI点击后聊天栏输入效果名)
if (areaProtection != null && areaProtection.handleEffectInput(p, msg)) {
e.setCancelled(true);
return;
}
// ===== 菜单聊天输入 =====
if (getMenu().isEditing(p.getName())) {
e.setCancelled(true);