From 6f9202859ddce6e74a54c3bce2e2a98a6664cb65 Mon Sep 17 00:00:00 2001 From: youpaishidifu <1@ypshidifu.cn> Date: Sun, 4 Oct 2026 19:25:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A2=86=E5=9C=B0=E5=A2=9E?= =?UTF-8?q?=E7=9B=8A=E8=8D=AF=E6=95=88=E7=AD=89=E7=BA=A7=E6=97=A0=E4=B8=8A?= =?UTF-8?q?=E9=99=90=EF=BC=8C=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7=E7=BB=84?= =?UTF-8?q?=E8=8D=AF=E6=95=88=E7=AD=89=E7=BA=A7=E4=B8=8A=E9=99=90=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:领地增益效果的等级完全没校验,管理员配了 255 级就会原样 生效(截图里出现的 Lv255 即源于此)。原版 /effect 的 amplifier 硬 上限是 255(对应药效强度 1~256),插件此前允许写入并施加远超原版 范围的等级。 修复(2026-10-04 任务4): - UserGroupManager 新增 maxEffectLevel 字段,默认 256 · 常量 DEFAULT_MAX_EFFECT_LEVEL = 256 集中定义原版上限 · user_group_config 建表补列 + ALTER 迁移(老库自动升级) · loadGroupConfigs 读取、saveGroupConfigToDB 加为第 14 列 · 新增 getPlayerMaxEffectLevel:普通玩家走原版 256,用户组按组配置 - AreaProtection 新增 getMaxGiveEffectLevel / clampGiveEffectLevel, 在全部 4 个应用点封顶:首次给予(applyRegionEffects)、热更新、 handleEnter、applyEffects;另在 PHP 字段推送(applyFieldToAreaConfig) 与 CLI 添加/编辑两处入口按同一上限做输入校验与提示 - WebManager 用户组同步双向补 max_effect_level(推 PHP + 回读) 规则:普通玩家(未加入任何用户组)严格按原版 256 封顶,严禁超限; 用户组玩家按组配置封顶,组里配多少就是多少,但任何情况下都不得 突破原版 256。原先散落各处的硬编码 255 已统一为该口径。 --- src/main/java/Sdf1_login/AreaProtection.java | 62 ++++++++++++++++--- .../java/Sdf1_login/UserGroupManager.java | 45 +++++++++++++- src/main/java/Sdf1_login/WebManager.java | 8 +++ 3 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/main/java/Sdf1_login/AreaProtection.java b/src/main/java/Sdf1_login/AreaProtection.java index 18e4d8e..cdddffe 100644 --- a/src/main/java/Sdf1_login/AreaProtection.java +++ b/src/main/java/Sdf1_login/AreaProtection.java @@ -3825,7 +3825,8 @@ public class AreaProtection implements Listener { PotionEffectType type = resolveEffectType(eff[0]); if (type == null) continue; - int lv = Integer.parseInt(eff[1]) - 1; + // ★ 药效等级封顶(2026-10-04 任务4):普通玩家按原版256,用户组按组配置 + int lv = clampGiveEffectLevel(Integer.parseInt(eff[1]), ac.owner) - 1; int dur = Integer.parseInt(eff[2]) * 20; PotionEffect existing = @@ -3891,7 +3892,8 @@ public class AreaProtection implements Listener { PotionEffectType type = resolveEffectType(eff[0]); if (type == null) continue; try { - int lv = Integer.parseInt(eff[1]) - 1; // MC amplifier从0开始 + // ★ 药效等级封顶(2026-10-04 任务4),与首次给予同一口径 + int lv = clampGiveEffectLevel(Integer.parseInt(eff[1]), ac.owner) - 1; // MC amplifier从0开始 int dur = Integer.parseInt(eff[2]) * 20; // 秒→tick expectedEffects.put(type, new int[]{lv, dur}); } catch (NumberFormatException ignored) {} @@ -4162,6 +4164,8 @@ public class AreaProtection implements Listener { catch (NumberFormatException ignored) {} try { duration = Integer.parseInt(parts[2]); } catch (NumberFormatException ignored) {} + // ★ 药效等级封顶(2026-10-04 任务4) + level = clampGiveEffectLevel(level, ac.owner); PotionEffectType type = resolveEffectType(effName); if (type != null) { p.addPotionEffect(new PotionEffect( @@ -4912,6 +4916,39 @@ public class AreaProtection implements Listener { return 5; } + /** + * ★ 领地增益【药效等级上限】(2026-10-04 任务4)。 + * 普通玩家(无用户组)严格按原版最大药效强度 256 封顶; + * 用户组玩家按组配置 max_effect_level,组里配多少就是多少。 + * + * @param ownerName 领地所有者(上限跟随领地所有者所属用户组,与数量上限一致口径) + * @return 药效强度上限,恒在 1~256 之间 + */ + public int getMaxGiveEffectLevel(String ownerName) { + try { + UserGroupManager ugm = plugin.getUserGroup(); + if (ugm != null) { + return ugm.getPlayerMaxEffectLevel(ownerName, + UserGroupManager.DEFAULT_MAX_EFFECT_LEVEL); + } + } catch (Exception ignored) {} + return UserGroupManager.DEFAULT_MAX_EFFECT_LEVEL; + } + + /** + * 把领地配置里的药效等级夹到该领地的合法上限内。 + * 所有写入/应用入口都必须过这一刀。 + * + * @param rawLevel 配置里写的原始药效强度 + * @param ownerName 领地所有者 + * @return 夹紧后的药效强度(1~256,且 <= 该领地用户组上限) + */ + public int clampGiveEffectLevel(int rawLevel, String ownerName) { + int cap = getMaxGiveEffectLevel(ownerName); + if (rawLevel < 1) return 1; + return rawLevel > cap ? cap : rawLevel; + } + public List getUserGroupNames() { List names = new ArrayList<>(); UserGroupManager ugm = plugin.getUserGroup(); @@ -5111,6 +5148,8 @@ public class AreaProtection implements Listener { catch (NumberFormatException ignored) {} try { duration = Integer.parseInt(parts[2]); } catch (NumberFormatException ignored) {} + // ★ 药效等级封顶(2026-10-04 任务4) + level = clampGiveEffectLevel(level, ac.owner); PotionEffectType type = resolveEffectType(effName); plugin.getLogger().info("[防护调试] 给予: " @@ -10696,11 +10735,13 @@ public class AreaProtection implements Listener { ac.giveEffects = new java.util.ArrayList<>( ac.giveEffects.subList(0, maxEff)); } + // ★ 药效等级按该领地用户组上限封顶(2026-10-04 任务4) + int maxLv = getMaxGiveEffectLevel(ac.owner); for (String[] ef : ac.giveEffects) { if (ef.length >= 2) { try { int lv = Integer.parseInt(ef[1]); - if (lv > 255) ef[1] = "255"; + if (lv > maxLv) ef[1] = String.valueOf(maxLv); else if (lv < 1) ef[1] = "1"; } catch (NumberFormatException ignored) {} } @@ -11169,9 +11210,11 @@ public class AreaProtection implements Listener { p.sendMessage("§c§l[添加增益效果] §f等级和秒数必须是数字"); return true; } - // ★ 验证等级和秒数范围 - if (effLv < 1 || effLv > 255) { - p.sendMessage("§c§l[添加增益效果] §f等级范围: 1~255"); + // ★ 验证等级和秒数范围(等级上限按用户组配置,2026-10-04 任务4) + int maxLvAdd = getMaxGiveEffectLevel(land.owner); + if (effLv < 1 || effLv > maxLvAdd) { + p.sendMessage("§c§l[添加增益效果] §f等级范围: 1~" + maxLvAdd); + p.sendMessage("§7上限说明: 普通玩家为原版上限 256,你当前可用的上限是 " + maxLvAdd); return true; } if (effDur < 1 || effDur > 3600) { @@ -11226,7 +11269,12 @@ public class AreaProtection implements Listener { p.sendMessage("§c请输入有效数字"); return true; } - if (newLevel < 1 || newLevel > 255) { p.sendMessage("§c等级范围1~255"); return true; } + int maxLvEdit = getMaxGiveEffectLevel(land.owner); + if (newLevel < 1 || newLevel > maxLvEdit) { + p.sendMessage("§c等级范围1~" + maxLvEdit); + p.sendMessage("§7上限说明: 普通玩家为原版上限 256,你当前可用的上限是 " + maxLvEdit); + return true; + } if (eff.length < 2) { String[] tmp = new String[3]; System.arraycopy(eff, 0, tmp, 0, eff.length); eff = tmp; land.giveEffects.set(idx - 1, eff); } eff[1] = String.valueOf(newLevel); p.sendMessage("§a§l[编辑增益] §f已将 §e" + eff[0] + " §f等级修改为 " + newLevel); diff --git a/src/main/java/Sdf1_login/UserGroupManager.java b/src/main/java/Sdf1_login/UserGroupManager.java index 92fb38c..3996705 100644 --- a/src/main/java/Sdf1_login/UserGroupManager.java +++ b/src/main/java/Sdf1_login/UserGroupManager.java @@ -52,7 +52,8 @@ public class UserGroupManager { + "max_lands INTEGER DEFAULT -1," // -1 = 使用全局值 + "default_perms TEXT DEFAULT '{}'," // JSON: 默认deny_*标志 + "is_permanent INTEGER DEFAULT 1," // 保留兼容 - + "duration_minutes INTEGER DEFAULT 0" // 保留兼容 + + "duration_minutes INTEGER DEFAULT 0," // 保留兼容 + + "max_effect_level INTEGER DEFAULT 256" // 药效等级上限,<=0=按原版256 + ")"); // 玩家↔用户组关联 @@ -78,6 +79,8 @@ public class UserGroupManager { try { st.executeUpdate("ALTER TABLE user_group_config ADD COLUMN renew_price INTEGER DEFAULT 0"); } catch (Exception ignored) {} // ★ 领地增益效果上限(2026-10-04 任务3):默认5个,<=0=不限 try { st.executeUpdate("ALTER TABLE user_group_config ADD COLUMN max_effects INTEGER DEFAULT 5"); } catch (Exception ignored) {} + // ★ 药效等级上限(2026-10-04 任务4):默认256=原版最大药效强度,<=0=按原版 + try { st.executeUpdate("ALTER TABLE user_group_config ADD COLUMN max_effect_level INTEGER DEFAULT 256"); } catch (Exception ignored) {} // duration_minutes已有(旧列),复用 st.close(); @@ -110,6 +113,8 @@ public class UserGroupManager { cfg.durationMinutes = rs.getLong("duration_minutes"); cfg.maxEffects = rs.getInt("max_effects"); if (rs.wasNull()) cfg.maxEffects = 5; + cfg.maxEffectLevel = rs.getInt("max_effect_level"); + if (rs.wasNull()) cfg.maxEffectLevel = UserGroupManager.DEFAULT_MAX_EFFECT_LEVEL; if (cfg.name != null && !cfg.name.isEmpty()) { groupConfigs.put(cfg.name, cfg); } @@ -131,8 +136,8 @@ public class UserGroupManager { + "(group_name, display_name, display_color," + " priority, land_price_per_sqm, max_lands, default_perms," + " home_limit, join_price, auto_renew, renew_price, duration_minutes," - + " max_effects)" - + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"); + + " max_effects, max_effect_level)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); ps.setString(1, cfg.name); ps.setString(2, cfg.displayName); ps.setString(3, cfg.displayColor); @@ -146,6 +151,7 @@ public class UserGroupManager { ps.setInt(11, cfg.renewPrice); ps.setLong(12, cfg.durationMinutes); ps.setInt(13, cfg.maxEffects); + ps.setInt(14, cfg.maxEffectLevel); ps.executeUpdate(); ps.close(); } catch (SQLException e) { @@ -980,6 +986,30 @@ public class UserGroupManager { return cfg.maxEffects; } + /** + * ★ 药效等级上限(2026-10-04 任务4)。 + * 普通玩家(无用户组)严格按原版最大药效强度 256 封顶; + * 用户组玩家按组配置 max_effect_level,配置多少就是多少。 + * 组配置 <=0 视为「不额外限制」,仍受原版 256 硬上限约束。 + * + * @param player 玩家名 + * @param globalDefault 无组时的全局默认(原版上限 256) + * @return 药效强度上限,恒 >=1 且 <=256 + */ + public int getPlayerMaxEffectLevel(String player, int globalDefault) { + int cap = DEFAULT_MAX_EFFECT_LEVEL; + if (globalDefault > 0 && globalDefault < cap) { + cap = globalDefault; + } + if (player != null && !player.isEmpty()) { + UserGroupConfig cfg = getHighestGroup(player); + if (cfg != null && cfg.maxEffectLevel > 0 && cfg.maxEffectLevel < cap) { + cap = cfg.maxEffectLevel; + } + } + return cap; + } + /** * 获取玩家的默认领地权限 JSON * 返回:组默认权限 或 空JSON "{}" @@ -1151,6 +1181,14 @@ public class UserGroupManager { // ==================== 配置类 ==================== + /** + * ★ 原版最大药效强度(2026-10-04 任务4)。 + * Minecraft 药效强度范围 1~256,amplifier = 强度 - 1,即 0~255, + * /effect 命令的 amplifier 参数硬上限就是 255。 + * 普通玩家(无用户组)一律以此为上限,严禁超限。 + */ + public static final int DEFAULT_MAX_EFFECT_LEVEL = 256; + public static class UserGroupConfig { public String name; public String displayName = ""; @@ -1160,6 +1198,7 @@ public class UserGroupManager { public int landPricePerSqm = -1; // -1 = 使用全局 public int maxLands = -1; // -1 = 使用全局 public int maxEffects = 5; // 领地增益效果上限,<=0=不限 + public int maxEffectLevel = DEFAULT_MAX_EFFECT_LEVEL; // 药效等级上限,<=0=按原版256 public String defaultPerms = "{}"; // JSON // Home相关 public int homeLimit = 0; // 0=跟随全局, >0=独立限制, -1=无限 diff --git a/src/main/java/Sdf1_login/WebManager.java b/src/main/java/Sdf1_login/WebManager.java index 756ea49..c096254 100644 --- a/src/main/java/Sdf1_login/WebManager.java +++ b/src/main/java/Sdf1_login/WebManager.java @@ -4039,6 +4039,7 @@ public class WebManager { gs.append("\"land_price_per_sqm\":").append(cfg.landPricePerSqm).append(","); gs.append("\"max_lands\":").append(cfg.maxLands).append(","); gs.append("\"max_effects\":").append(cfg.maxEffects).append(","); + gs.append("\"max_effect_level\":").append(cfg.maxEffectLevel).append(","); gs.append("\"home_limit\":").append(cfg.homeLimit).append(","); gs.append("\"join_price\":").append(cfg.joinPrice).append(","); gs.append("\"auto_renew\":").append(cfg.autoRenew ? 1 : 0).append(","); @@ -4437,6 +4438,13 @@ public class WebManager { try { cfg.maxEffects = Integer.parseInt(maxEffStr); } catch (Exception ignored) { cfg.maxEffects = 5; } } + // ★ 药效等级上限(2026-10-04 任务4) + String maxEffLvStr = extractJsonField(obj, "max_effect_level"); + if (!maxEffLvStr.isEmpty()) { + try { cfg.maxEffectLevel = Integer.parseInt(maxEffLvStr); } + catch (Exception ignored) { cfg.maxEffectLevel = UserGroupManager.DEFAULT_MAX_EFFECT_LEVEL; } + } + if (cfg.maxEffectLevel <= 0) cfg.maxEffectLevel = UserGroupManager.DEFAULT_MAX_EFFECT_LEVEL; String homeLimStr = extractJsonField(obj, "home_limit"); if (!homeLimStr.isEmpty()) try { cfg.homeLimit = Integer.parseInt(homeLimStr); } catch (Exception ignored) {} String joinStr = extractJsonField(obj, "join_price");