修复 denyMove 对访客/路人失效:GUI显示已禁用但实际畅通无阻
Check Source / check (push) Successful in 3s
Auto Release / build (push) Successful in 2m20s
Simple Test / test (push) Successful in 1s
Test Env / test (push) Successful in 1s

现象:领地访客授权页显示「移动 已禁用」,玩家在领地内却能自由走动。

根因:getEffectiveDeny 是所有 deny* 权限的共用入口,其第3步
    if (level == PermissionLevel.VISITOR) return false;
  对全部权限无条件豁免。denyMove 走同一入口,访客在此被放行,
  永远到不了第4步读 ac.denyMove。而 GUI(AreaGUIManager:586)
  显示读的正是 land.denyMove=true —— 显示与实际判定脱节。

判定链(修复前,访客):
  第1步 非ADMIN/OWNER → 不豁免
  第2步 playerPerms 无 denyMove 键 → containsKey=false,不命中
  第3步 level==VISITOR → return false ← 绕过点
  第4步 getLandDefaultDeny(ac,"denyMove")  永远到不了

修复(按用户决策:仅 denyMove 改,其余权限保持现状):
  第3步增加 denyMove 特例 —— 访客若无 per-player 显式 denyMove,
  不再豁免,继续落到第4步按领地默认 denyMove 判定。
  level==null(纯路人)本就落在第4步,行为正确,未改动。

顺带恢复 logDenyExempt 诊断输出(此前整段被注释,
是当初现场无法定位该问题的直接原因)。

验证:离线回归测试 13/13 通过,覆盖 ADMIN/OWNER 豁免、
per-player 显式放行与禁止、访客回落、路人回落、白名单访客,
并断言 denyBlockBreak/denyContainer/denyBlockPlace/denyWax
的访客豁免语义未被破坏。mvn -o clean package 编译通过。
This commit is contained in:
youpaishidifu
2026-10-04 18:47:05 +08:00
parent 494ab22227
commit f2808a5923
+12 -5
View File
@@ -2935,11 +2935,20 @@ public class AreaProtection implements Listener {
}
// 3) 访客豁免(该玩家没有任何 per-player 显式配置时才生效)
// ★ 2026-10-04 修复:denyMove 不再对访客豁免。
// 原因:领地 GUI 的"移动"开关读的是 ac.denyMove(领地默认),
// 而访客在此处被无条件 return false,实际畅通无阻 —— 显示与行为脱节。
// 访客若无 per-player 显式 denyMove(第 2 步未命中),就继续落到第 4 步,
// 按领地默认 denyMove 判定,与"移动 已禁用"的显示保持一致。
// 其余 deny* 权限的访客豁免语义保持不变。
if (level == PermissionLevel.VISITOR) {
return false;
if (!"denyMove".equals(permName)) {
return false;
}
}
// 4) 回退到领地默认权限
// ★ level==null(纯路人:无白名单、无权限行)本就走这里,行为正确,未改动。
return getLandDefaultDeny(ac, permName);
}
@@ -3650,18 +3659,16 @@ public class AreaProtection implements Listener {
int landId = getLandIdFromDb(ac.name);
PermRow row = landId > 0 ? findPermRow(landId, p.getName()) : null;
String name = p.getName();
/* plugin.getLogger().info("[防护][移动豁免诊断] 场景=" + scene
plugin.getLogger().info("[防护][移动豁免诊断] 场景=" + scene
+ " 领地=" + ac.name
+ " 玩家=" + name
+ " 码点=" + java.util.Arrays.toString(name.codePoints().toArray())
+ " normName=" + normName(name)
+ " level=" + lvl
+ " 全局管理员=" + isAreaAdmin(p)
+ " 领地主=" + (ac.owner != null && samePlayer(name, ac.owner))
+ " 白名单=" + isPlayerWhitelisted(name, ac)
+ " 访客行=" + (row == null ? "无"
: (row.playerName + "/" + row.role + "/exp=" + row.expiresAt + "/" + row.permissions))
+ " 领地默认denyMove=" + ac.denyMove);*/
+ " 领地默认denyMove=" + ac.denyMove);
} catch (Exception ignored) {
}
}