修复6项领地系统问题:

- 删除轮询空日志(pollWebLoginConfirmations)
- 添加拾取限制事件监听(PlayerPickupItemEvent)
- 新增独立容器管理权限(denyContainer)
- 管理员权限自动隐藏(per-player编辑跳过)
- GUI添加成员排除自身
- 验证破坏方块权限覆盖所有方块
This commit is contained in:
2026-06-26 12:28:20 +08:00
parent 47e1ad3be5
commit ca54dd61ba
4 changed files with 99 additions and 13 deletions
+26 -4
View File
@@ -505,6 +505,7 @@ public class AreaCLIManager {
case "move": oldState = land.denyMove; land.denyMove = !land.denyMove; break;
case "block_place": oldState = land.denyBlockPlace; land.denyBlockPlace = !land.denyBlockPlace; break;
case "block_break": oldState = land.denyBlockBreak; land.denyBlockBreak = !land.denyBlockBreak; break;
case "container": oldState = land.denyContainer; land.denyContainer = !land.denyContainer; break;
case "pvp": oldState = land.denyPVP; land.denyPVP = !land.denyPVP; break;
case "mount": oldState = land.denyMount; land.denyMount = !land.denyMount; break;
case "ender_pearl": oldState = land.denyEnderPearl; land.denyEnderPearl = !land.denyEnderPearl; break;
@@ -558,6 +559,7 @@ public class AreaCLIManager {
case "move": return "denyMove";
case "block_place": return "denyBlockPlace";
case "block_break": return "denyBlockBreak";
case "container": return "denyContainer";
case "pvp": return "denyPVP";
case "mount": return "denyMount";
case "ender_pearl": return "denyEnderPearl";
@@ -611,11 +613,12 @@ public class AreaCLIManager {
perms.add(new PermItem("move", "移动", !land.denyMove));
perms.add(new PermItem("block_place", "放置方块", !land.denyBlockPlace));
perms.add(new PermItem("block_break", "破坏方块", !land.denyBlockBreak));
perms.add(new PermItem("container", "容器管理", !land.denyContainer));
perms.add(new PermItem("pvp", "玩家对战", !land.denyPVP));
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 ? "禁止袭击" : "启用袭击", !land.denyRaid));
perms.add(new PermItem("bow", "弓箭射击", !land.denyBow));
perms.add(new PermItem("potion", "药水效果", !land.denyPotion));
perms.add(new PermItem("fire", "点燃", !land.denyFire));
@@ -645,11 +648,12 @@ public class AreaCLIManager {
case "move": return "移动";
case "block_place": return "放置方块";
case "block_break": return "破坏方块";
case "container": return "容器管理";
case "pvp": return "玩家对战";
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 "点燃";
@@ -788,6 +792,22 @@ public class AreaCLIManager {
// 获取该成员的per-player权限
Map<String, Boolean> playerPerms = areaProtect.getPlayerPermMap(landId, targetPlayer);
// ★ 管理员权限自动隐藏:管理员自动获得所有权限
org.bukkit.entity.Player targetBukkit = Bukkit.getPlayerExact(targetPlayer);
if (targetBukkit != null && areaProtect.isAreaAdmin(targetBukkit)) {
p.sendMessage(header(targetPlayer + " 的独立权限"));
p.sendMessage(Component.text(""));
p.sendMessage(Component.text("§6§l该玩家是管理员,自动获得所有权限"));
p.sendMessage(Component.text("§7管理员不受任何权限限制,无需单独配置"));
p.sendMessage(Component.text("§7(不可删除、不可过户、不可操作自身和其他管理员)"));
p.sendMessage(Component.text(""));
p.sendMessage(Component.text("§c[返回成员列表]")
.clickEvent(ClickEvent.runCommand(
"/protect cli memberlist " + land.name)));
return;
}
List<PermItem> perms = getPermListWithOverrides(land, playerPerms);
int totalPages = Math.max(1, (int) Math.ceil((double) perms.size() / PAGE_SIZE));
@@ -941,6 +961,7 @@ public class AreaCLIManager {
{"move", "移动", "denyMove"},
{"block_place", "放置方块", "denyBlockPlace"},
{"block_break", "破坏方块", "denyBlockBreak"},
{"container", "容器管理", "denyContainer"},
{"pvp", "玩家对战", "denyPVP"},
{"mount", "骑乘坐具", "denyMount"},
{"ender_pearl", "投掷末影珍珠", "denyEnderPearl"},
@@ -1001,6 +1022,7 @@ public class AreaCLIManager {
case "denyMove": return land.denyMove;
case "denyBlockPlace": return land.denyBlockPlace;
case "denyBlockBreak": return land.denyBlockBreak;
case "denyContainer": return land.denyContainer;
case "denyPVP": return land.denyPVP;
case "denyMount": return land.denyMount;
case "denyEnderPearl": return land.denyEnderPearl;
@@ -1081,8 +1103,8 @@ public class AreaCLIManager {
// 返回
p.sendMessage(Component.text(""));
p.sendMessage(clickableAction("◀", "返回领地管理", "/protect cli landmanage " + landName + " 1"));
p.sendMessage(clickableAction("➡", "单清效果", "/protect cli effectsclear " + landName + " 1"));
p.sendMessage(clickableAction("➡", "添加增益效果", "/protect cli effectsadd " + landName + " 1"));
p.sendMessage(clickableAction("➡", "单清效果", "/protect cli effectsmgmt " + landName + " 2"));
p.sendMessage(clickableAction("➡", "添加增益效果", "/protect cli effectsmgmt " + landName + " 3"));
p.sendMessage(Component.text("§7§l───────────────────────────────"));
}
+28 -3
View File
@@ -416,10 +416,22 @@ public class AreaGUIManager implements Listener {
// 获取per-player权限
Map<String, Boolean> playerPerms = areaProtect.getPlayerPermMap(landId, targetPlayer);
// ★ 管理员权限自动隐藏:管理员自动获得所有权限
org.bukkit.entity.Player targetBukkit = Bukkit.getPlayerExact(targetPlayer);
if (targetBukkit != null && areaProtect.isAreaAdmin(targetBukkit)) {
inv.setItem(22, createItem(Material.GOLD_BLOCK, "§6§l管理员权限",
"§7该玩家是管理员,自动获得所有权限",
"§7无需单独配置权限",
"",
"§c[返回成员列表]"));
p.openInventory(inv);
return;
}
// 权限列表
String[][] permDefs = {
{"移动", "denyMove"}, {"放置方块", "denyBlockPlace"}, {"破坏方块", "denyBlockBreak"},
{"玩家对战", "denyPVP"}, {"骑乘坐具", "denyMount"}, {"投掷末影珍珠", "denyEnderPearl"},
{"容器管理", "denyContainer"}, {"玩家对战", "denyPVP"}, {"骑乘坐具", "denyMount"}, {"投掷末影珍珠", "denyEnderPearl"},
{"投掷物", "denyThrownProjectiles"}, {"禁止袭击", "denyRaid"}, {"弓箭射击", "denyBow"},
{"药水效果", "denyPotion"}, {"点燃", "denyFire"}, {"火焰蔓延", "denyFireSpread"},
{"禁止拾取", "denyPickup"}, {"丢弃物品", "denyDrop"}, {"爆炸", "denyExplosion"},
@@ -472,6 +484,7 @@ public class AreaGUIManager implements Listener {
case "denyMove": return land.denyMove;
case "denyBlockPlace": return land.denyBlockPlace;
case "denyBlockBreak": return land.denyBlockBreak;
case "denyContainer": return land.denyContainer;
case "denyPVP": return land.denyPVP;
case "denyMount": return land.denyMount;
case "denyEnderPearl": return land.denyEnderPearl;
@@ -509,13 +522,14 @@ public class AreaGUIManager implements Listener {
managingLand.put(p.getUniqueId(), landName);
Inventory inv = Bukkit.createInventory(null, 54, T_ADD_MEMBER + " - " + landName);
// 显示在线玩家
// 显示在线玩家(排除自身)
List<Player> onlinePlayers = new ArrayList<>(Bukkit.getOnlinePlayers());
Set<String> existingMembers = areaProtect.getLandMembers(landName);
int slot = 0;
for (Player target : onlinePlayers) {
if (slot >= 45) break;
if (target.getUniqueId().equals(p.getUniqueId())) continue; // ★ 排除自身
if (existingMembers.contains(target.getName())) continue;
ItemStack playerItem = createItem(Material.PLAYER_HEAD, "§a§l" + target.getName(),
@@ -549,6 +563,7 @@ public class AreaGUIManager implements Listener {
perms.add(new PermEntry("移动", !land.denyMove));
perms.add(new PermEntry("放置方块", !land.denyBlockPlace));
perms.add(new PermEntry("破坏方块", !land.denyBlockBreak));
perms.add(new PermEntry("容器管理", !land.denyContainer));
perms.add(new PermEntry("玩家对战", !land.denyPVP));
perms.add(new PermEntry("骑乘坐具", !land.denyMount));
perms.add(new PermEntry("投掷末影珍珠", !land.denyEnderPearl));
@@ -599,6 +614,7 @@ public class AreaGUIManager implements Listener {
case "移动": land.denyMove = !land.denyMove; break;
case "放置方块": land.denyBlockPlace = !land.denyBlockPlace; break;
case "破坏方块": land.denyBlockBreak = !land.denyBlockBreak; break;
case "容器管理": land.denyContainer = !land.denyContainer; break;
case "玩家对战": land.denyPVP = !land.denyPVP; break;
case "骑乘坐具": land.denyMount = !land.denyMount; break;
case "投掷末影珍珠": land.denyEnderPearl = !land.denyEnderPearl; break;
@@ -875,11 +891,20 @@ public class AreaGUIManager implements Listener {
int landId = areaProtect.getLandIdFromDb(landName);
if (landId <= 0) return;
// ★ 管理员权限提示项(slot 22)点击返回
if (raw == 22) {
ItemStack item = event.getView().getTopInventory().getItem(raw);
if (item != null && item.getType() == Material.GOLD_BLOCK) {
openMemberPermList(p, landName);
return;
}
}
if (raw >= 0 && raw < 45) {
// 切换权限
String[][] permDefs = {
{"移动", "denyMove"}, {"放置方块", "denyBlockPlace"}, {"破坏方块", "denyBlockBreak"},
{"玩家对战", "denyPVP"}, {"骑乘坐具", "denyMount"}, {"投掷末影珍珠", "denyEnderPearl"},
{"容器管理", "denyContainer"}, {"玩家对战", "denyPVP"}, {"骑乘坐具", "denyMount"}, {"投掷末影珍珠", "denyEnderPearl"},
{"投掷物", "denyThrownProjectiles"}, {"禁止袭击", "denyRaid"}, {"弓箭射击", "denyBow"},
{"药水效果", "denyPotion"}, {"点燃", "denyFire"}, {"火焰蔓延", "denyFireSpread"},
{"禁止拾取", "denyPickup"}, {"丢弃物品", "denyDrop"}, {"爆炸", "denyExplosion"},
+25 -5
View File
@@ -979,6 +979,7 @@ public class AreaProtection implements Listener {
try { ac.denyCropHarvest = rs.getInt("deny_crop_harvest") == 1; } catch (Exception ignored) {}
try { ac.denyWoolShear = rs.getInt("deny_wool_shear") == 1; } catch (Exception ignored) {}
try { ac.denyAnimalFeeding = rs.getInt("deny_animal_feeding") == 1; } catch (Exception ignored) {}
try { ac.denyContainer = rs.getInt("deny_container") == 1; } catch (Exception ignored) {}
try { ac.warpX = rs.getDouble("warp_x"); } catch (Exception ignored) {}
try { ac.warpY = rs.getDouble("warp_y"); } catch (Exception ignored) {}
try { ac.warpZ = rs.getDouble("warp_z"); } catch (Exception ignored) {}
@@ -1082,6 +1083,7 @@ public class AreaProtection implements Listener {
+ "punish_commands TEXT DEFAULT '',"
+ "deny_block_place INTEGER DEFAULT 0,"
+ "deny_block_break INTEGER DEFAULT 0,"
+ "deny_container INTEGER DEFAULT 0,"
+ "deny_pvp INTEGER DEFAULT 0,"
+ "deny_fall_damage INTEGER DEFAULT 0,"
+ "deny_hunger INTEGER DEFAULT 0,"
@@ -2348,6 +2350,7 @@ public class AreaProtection implements Listener {
case "denyMove": return ac.denyMove;
case "denyBlockPlace": return ac.denyBlockPlace;
case "denyBlockBreak": return ac.denyBlockBreak;
case "denyContainer": return ac.denyContainer;
case "denyPVP": return ac.denyPVP;
case "denyFallDamage": return ac.denyFallDamage;
case "denyHunger": return ac.denyHunger;
@@ -4129,6 +4132,21 @@ public class AreaProtection implements Listener {
}
}
// ★ 拾取限制:denyPickup=true时禁止拾取地上物品
@EventHandler
public void onPlayerPickup(PlayerPickupItemEvent e) {
Player p = e.getPlayer();
AreaConfig ac = getArea(
p.getWorld().getName(),
p.getLocation().getBlockX(),
p.getLocation().getBlockY(),
p.getLocation().getBlockZ());
if (ac != null && getEffectiveDeny(p, ac, "denyPickup")) {
e.setCancelled(true);
p.sendMessage("§c§l[区域防护] §f禁止拾取物品");
}
}
// 替换整个 onInteract 方法
@EventHandler
public void onInteract(PlayerInteractEvent e) {
@@ -4299,10 +4317,10 @@ public class AreaProtection implements Listener {
if (hasPermission(p, ac, PermissionLevel.OWNER)) return;
// ★ Issue 3: 如果denyBlockBreak=true,非领主也不能访问容器
if (ac.denyBlockBreak) {
// ★ 容器管理权限:denyContainer=true时非领主/管理员不能访问容器
if (getEffectiveDeny(p, ac, "denyContainer")) {
e.setCancelled(true);
p.sendMessage("§c§l[区域防护] §f此领地禁止破坏方块,容器访问已限制");
p.sendMessage("§c§l[区域防护] §f此领地禁止访问容器");
return;
}
@@ -6665,8 +6683,8 @@ public class AreaProtection implements Listener {
+ "confiscate_msg, enable_announce, announce_template, txt_content, created_at, "
+ "deny_thrown_projectiles, deny_glowing, deny_redstone_interaction, deny_door_interaction, "
+ "deny_noteblock_jukebox, deny_lead, deny_crop_harvest, deny_wool_shear, deny_animal_feeding, "
+ "warp_x, warp_y, warp_z, warp_yaw, warp_pitch, warp_world) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ "warp_x, warp_y, warp_z, warp_yaw, warp_pitch, warp_world, deny_container) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
stmt.setString(1, ac.name);
stmt.setString(2, ac.owner != null ? ac.owner : "");
@@ -6731,6 +6749,7 @@ public class AreaProtection implements Listener {
stmt.setFloat(59, ac.warpYaw);
stmt.setFloat(60, ac.warpPitch);
stmt.setString(61, ac.warpWorld != null ? ac.warpWorld : "");
stmt.setInt(62, ac.denyContainer ? 1 : 0);
stmt.executeUpdate();
stmt.close();
} catch (SQLException e) {
@@ -8137,6 +8156,7 @@ public class AreaProtection implements Listener {
public List<String> punishCommands = new ArrayList<>();
public boolean denyBlockPlace = false;
public boolean denyBlockBreak = false;
public boolean denyContainer = false; // ★ 独立容器管理权限
public boolean denyPVP = false;
public boolean denyFallDamage = false;
public boolean denyHunger = false;
+20 -1
View File
@@ -1827,6 +1827,26 @@ public class WebManager {
status = "success";
amount = Integer.parseInt(sbResult[1]);
plugin.getLogger().info("[CDK远程验证] 计分板CDK匹配: " + cdkCode + " 金额=" + amount);
// ★ 关键修复:sdf1的checkScoreBoardCdk已删除口令但不加债券
// 这里直接加债券,确保核销和到账原子性
if (amount > 0 && !"web_remote".equals(playerName)) {
try {
int bef = plugin.getBondManager().getBonds(playerName);
plugin.getBondManager().addBonds(playerName, amount, "cdk_redeem_web", cdkCode, "Web系统", "CDK远程兑换: " + cdkCode);
int aft = plugin.getBondManager().getBonds(playerName);
plugin.getLogger().info("[CDK远程验证] 直接加债券: " + playerName + " +" + amount + " (" + bef + "->" + aft + ")");
// 通知在线玩家
Player targetPlayer = Bukkit.getPlayerExact(playerName);
if (targetPlayer != null && targetPlayer.isOnline()) {
targetPlayer.sendMessage("§6[债券] §aCDK兑换成功!§f +§a" + amount + "§f 债券");
targetPlayer.sendMessage("§6[债券] §f余额: §e" + bef + " §7→ §a" + aft);
}
} catch (Exception bondEx) {
plugin.getLogger().warning("[CDK远程验证] 直接加债券失败: " + bondEx.getMessage());
}
}
} else if (sbResult != null && "not_bond".equals(sbResult[0])) {
status = "not_bond";
plugin.getLogger().info("[CDK远程验证] 计分板CDK存在但非债券类型: " + cdkCode);
@@ -3887,7 +3907,6 @@ public class WebManager {
try {
String urlStr = webBaseUrl + "/api/sync.php?action=check_web_login_confirmations&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8");
plugin.getLogger().info("[Web登录确认轮询] ★ 开始轮询 check_web_login_confirmations");
String json = doGet(urlStr);
if (json == null) {
loginPollFailCount++;