diff --git a/src/main/java/Sdf1_login/CDKManager.java b/src/main/java/Sdf1_login/CDKManager.java index 3a79344..8e7b56c 100644 --- a/src/main/java/Sdf1_login/CDKManager.java +++ b/src/main/java/Sdf1_login/CDKManager.java @@ -170,6 +170,21 @@ public class CDKManager { if ("points".equals(input.type)) { handlePointsInput(p, msg.trim(), input.context); + return; + } + + if ("gift_target".equals(input.type)) { + // 赠予用户组:输入目标玩家名 + String targetName = msg.trim(); + if (!targetName.isEmpty()) { + GUIManager guiMgr = plugin.getGui(); + if (guiMgr != null) { + guiMgr.handleGiftTargetInput(p, targetName); + } + } else { + p.sendMessage("§c请输入有效的玩家名"); + } + return; } } diff --git a/src/main/java/Sdf1_login/DatabaseManager.java b/src/main/java/Sdf1_login/DatabaseManager.java index 811f65c..e7259a0 100644 --- a/src/main/java/Sdf1_login/DatabaseManager.java +++ b/src/main/java/Sdf1_login/DatabaseManager.java @@ -301,6 +301,56 @@ public class DatabaseManager { } } + // ==================== 自动续费偏好 ==================== + + /** 获取玩家的自动续费偏好 */ + public boolean getPlayerAutoRenew(String player, String group) { + try { + Statement st = db.createStatement(); + st.execute("CREATE TABLE IF NOT EXISTS player_auto_renew (player_name TEXT NOT NULL, group_name TEXT NOT NULL, auto_renew INTEGER DEFAULT 0, PRIMARY KEY(player_name, group_name))"); + String sql = "SELECT auto_renew FROM player_auto_renew WHERE player_name = ? AND group_name = ?"; + PreparedStatement ps = db.prepareStatement(sql); + ps.setString(1, player); + ps.setString(2, group); + ResultSet rs = ps.executeQuery(); + if (rs.next()) return rs.getInt("auto_renew") == 1; + } catch (Exception ignored) {} + return false; + } + + /** 设置玩家的自动续费偏好 */ + public void setPlayerAutoRenew(String player, String group, boolean value) { + try { + Statement st = db.createStatement(); + st.execute("CREATE TABLE IF NOT EXISTS player_auto_renew (player_name TEXT NOT NULL, group_name TEXT NOT NULL, auto_renew INTEGER DEFAULT 0, PRIMARY KEY(player_name, group_name))"); + String sql = "INSERT OR REPLACE INTO player_auto_renew (player_name, group_name, auto_renew) VALUES (?, ?, ?)"; + PreparedStatement ps = db.prepareStatement(sql); + ps.setString(1, player); + ps.setString(2, group); + ps.setInt(3, value ? 1 : 0); + ps.executeUpdate(); + } catch (Exception ignored) {} + } + + /** 获取玩家所有自动续费开启的组 */ + public List> getAutoRenewGroups(String player) { + List> result = new ArrayList<>(); + try { + Statement st = db.createStatement(); + st.execute("CREATE TABLE IF NOT EXISTS player_auto_renew (player_name TEXT NOT NULL, group_name TEXT NOT NULL, auto_renew INTEGER DEFAULT 0, PRIMARY KEY(player_name, group_name))"); + String sql = "SELECT group_name FROM player_auto_renew WHERE player_name = ? AND auto_renew = 1"; + PreparedStatement ps = db.prepareStatement(sql); + ps.setString(1, player); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Map row = new HashMap<>(); + row.put("group_name", rs.getString("group_name")); + result.add(row); + } + } catch (Exception ignored) {} + return result; + } + public void close() { try { if (db != null && !db.isClosed()) diff --git a/src/main/java/Sdf1_login/GUIManager.java b/src/main/java/Sdf1_login/GUIManager.java index f09e39c..ff60ae5 100644 --- a/src/main/java/Sdf1_login/GUIManager.java +++ b/src/main/java/Sdf1_login/GUIManager.java @@ -45,6 +45,8 @@ public class GUIManager implements Listener { "§6§l邀请数据"; public static final String T_USER_MGMT = "§6§l用户管理"; + public static final String T_USER_GROUP = + "§6§l用户组管理"; public static final String T_TASK_CENTER = "§6§l任务中心"; private final Map userMgmtPages = new HashMap<>(); @@ -984,6 +986,13 @@ public class GUIManager implements Listener { return; } + // ===== 用户组管理 ===== + if (T_USER_GROUP.equals(title)) { + event.setCancelled(true); + handleUserGroupClick(p, raw, event.isLeftClick(), event.isRightClick(), event.isShiftClick()); + return; + } + // ===== 打包确认 ===== if ("§6§l选择包装方式".equals(title)) { event.setCancelled(true); @@ -2768,6 +2777,301 @@ public class GUIManager implements Listener { plugin.getConfig2().adminTag); } + // ==================== 用户组管理GUI ==================== + + /** 打开用户组管理主界面 */ + public void openUserGroup(Player p) { + UserGroupManager ugm = plugin.getUserGroup(); + if (ugm == null) { p.sendMessage("§c用户组系统未初始化"); return; } + + Inventory g = Bukkit.createInventory(null, 54, T_USER_GROUP); + + int bonds = plugin.getBonds().getBonds(p.getName()); + g.setItem(4, mkItem(Material.EMERALD, "§b§l我的债券: " + bonds + " 张", "§7用于购买/续费用户组")); + + // Row1 (9-17): 可购买的用户组 + List allGroups = ugm.getAllGroups(); + int slot = 9; + for (UserGroupManager.UserGroupConfig cfg : allGroups) { + if (slot > 17) break; + if (cfg.joinPrice <= 0) continue; // 不开放付费的组不显示 + + boolean isMember = ugm.isPlayerInGroup(p.getName(), cfg.name); + String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; + + if (isMember) { + // 已加入 → 显示在 Row2 + continue; + } + + Material mat = isMember ? Material.LIME_DYE : Material.WHITE_DYE; + List lore = new ArrayList<>(); + lore.add("§7价格: §e" + cfg.joinPrice + " 张债券"); + if (cfg.durationMinutes > 0) { + long days = cfg.durationMinutes / 1440; + long hours = (cfg.durationMinutes % 1440) / 60; + String dur = days > 0 ? days + "天" : hours + "小时"; + lore.add("§7有效期: §e" + dur); + } else { + lore.add("§7有效期: §a永久"); + } + if (cfg.renewPrice > 0) { + lore.add("§7续费价格: §e" + cfg.renewPrice + " 张债券"); + } + lore.add(""); + lore.add("§a左键: 购买给自己"); + lore.add("§b右键: 赠送给他人"); + + g.setItem(slot, mkItem(mat, cfg.displayColor + "§l" + displayName + " §7(购买)", lore.toArray(new String[0]))); + slot++; + } + + // Row2 (18-26): 我的用户组 + slot = 18; + List> myGroups = ugm.getPlayerGroups(p.getName()); + for (Map grp : myGroups) { + if (slot > 26) break; + String grpName = String.valueOf(grp.get("group_name")); + UserGroupManager.UserGroupConfig cfg = ugm.getGroupConfig(grpName); + if (cfg == null) continue; + + String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; + long expiry = ((Number) grp.getOrDefault("expiry_time", 0)).longValue(); + long now = System.currentTimeMillis(); + + List lore = new ArrayList<>(); + if (expiry > 0) { + if (expiry <= now) { + lore.add("§c已过期"); + } else { + long remainMs = expiry - now; + long remainMin = remainMs / 60000; + long rDays = remainMin / 1440; + long rHours = (remainMin % 1440) / 60; + lore.add("§7剩余: §e" + (rDays > 0 ? rDays + "天" : rHours + "小时")); + lore.add("§7到期: §7" + new java.text.SimpleDateFormat("MM-dd HH:mm").format(new java.util.Date(expiry))); + } + } else { + lore.add("§7有效期: §a永久"); + } + // 自动续费状态 + boolean autoRenew = getAutoRenew(p.getName(), grpName); + lore.add("§7自动续费: " + (autoRenew ? "§a开启" : "§c关闭")); + lore.add(""); + lore.add("§a左键: 续费"); + lore.add("§b右键: 赠送给他人"); + lore.add("§eShift+右键: " + (autoRenew ? "§c关闭" : "§a开启") + "自动续费"); + + g.setItem(slot, mkItem(Material.LIME_DYE, cfg.displayColor + "§l" + displayName, lore.toArray(new String[0]))); + slot++; + } + + // Row4 (40): 赠送入口 + g.setItem(40, mkItem(Material.SPECTRAL_ARROW, "§e§l赠予用户组", "§7为其他玩家购买/续费用户组")); + + // Row5 (49): 返回 + g.setItem(49, mkItem(Material.ARROW, "§7返回")); + + fillBg(g); + p.openInventory(g); + } + + /** 处理用户组GUI点击 */ + public boolean handleUserGroupClick(Player p, int raw, boolean left, boolean right, boolean shift) { + UserGroupManager ugm = plugin.getUserGroup(); + if (ugm == null) return false; + + if (raw == 49) { openMain(p); return true; } // 返回 + + // 赠送按钮 + if (raw == 40) { + p.closeInventory(); + p.sendMessage("§e§l[赠予] §7请输入要赠予的玩家名:"); + plugin.getCDK().requestInput(p, "gift_target", ""); + return true; + } + + // Row1: 可购买的组 (9-17) + if (raw >= 9 && raw <= 17) { + ItemStack item = p.getOpenInventory().getTopInventory().getItem(raw); + if (item == null || item.getType() == Material.GRAY_STAINED_GLASS_PANE) return false; + String grpName = extractGroupNameFromItem(item); + if (grpName == null) return false; + + UserGroupManager.UserGroupConfig cfg = ugm.getGroupConfig(grpName); + if (cfg == null) return false; + + if (left && !right) { + // 购买给自己 + p.closeInventory(); + p.sendMessage("§7正在购买 §e" + (cfg.displayName.isEmpty() ? cfg.name : cfg.displayName) + " §7..."); + String err = ugm.joinGroupByPrice(p.getName(), cfg.name); + if (err != null) { + p.sendMessage("§c购买失败: " + err); + } else { + p.sendMessage("§a§l购买成功! §7你已加入用户组 §e" + (cfg.displayName.isEmpty() ? cfg.name : cfg.displayName)); + } + return true; + } else if (right && !left) { + // 赠送给他人 + p.closeInventory(); + // 记住赠送的组名 + pendingGiftGroup.put(p.getName(), grpName); + p.sendMessage("§e§l[赠予] §7请输入要赠予的玩家名:"); + plugin.getCDK().requestInput(p, "gift_target", grpName); + return true; + } + } + + // Row2: 我的组 (18-26) + if (raw >= 18 && raw <= 26) { + ItemStack item = p.getOpenInventory().getTopInventory().getItem(raw); + if (item == null || item.getType() == Material.GRAY_STAINED_GLASS_PANE) return false; + String grpName = extractGroupNameFromItem(item); + if (grpName == null) return false; + + UserGroupManager.UserGroupConfig cfg = ugm.getGroupConfig(grpName); + if (cfg == null) return false; + + if (shift && right) { + // Shift+右键: 切换自动续费 + boolean current = getAutoRenew(p.getName(), grpName); + setAutoRenew(p.getName(), grpName, !current); + p.sendMessage("§a自动续费已" + (!current ? "开启" : "关闭") + ": §e" + (cfg.displayName.isEmpty() ? cfg.name : cfg.displayName)); + openUserGroup(p); // 刷新界面 + return true; + } + + if (left && !right) { + // 续费 + p.closeInventory(); + p.sendMessage("§7正在续费 §e" + (cfg.displayName.isEmpty() ? cfg.name : cfg.displayName) + " §7..."); + String err = ugm.renewGroup(p.getName(), cfg.name); + if (err != null) { + p.sendMessage("§c续费失败: " + err); + } else { + p.sendMessage("§a§l续费成功! §7用户组 §e" + (cfg.displayName.isEmpty() ? cfg.name : cfg.displayName) + " §7已续期"); + } + return true; + } else if (right && !left && !shift) { + // 赠送给他人 + p.closeInventory(); + pendingGiftGroup.put(p.getName(), grpName); + p.sendMessage("§e§l[赠予] §7请输入要赠予的玩家名:"); + plugin.getCDK().requestInput(p, "gift_target", grpName); + return true; + } + } + + return false; + } + + /** 处理赠予玩家名输入 */ + public void handleGiftTargetInput(Player p, String targetName) { + String grpName = pendingGiftGroup.remove(p.getName()); + if (grpName == null) return; + + UserGroupManager ugm = plugin.getUserGroup(); + if (ugm == null) { p.sendMessage("§c用户组系统未初始化"); return; } + + UserGroupManager.UserGroupConfig cfg = ugm.getGroupConfig(grpName); + if (cfg == null) { p.sendMessage("§c用户组不存在: " + grpName); return; } + + String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; + + // 检查目标玩家是否存在 + DatabaseManager dbMgr = plugin.getDb(); + if (dbMgr != null && !dbMgr.userExists(targetName)) { + p.sendMessage("§c玩家 §e" + targetName + " §c不存在"); + return; + } + + // 检查是否已加入 + boolean isTargetMember = ugm.isPlayerInGroup(targetName, grpName); + if (isTargetMember) { + // 目标已加入 → 续费 + p.sendMessage("§7玩家 §e" + targetName + " §7已拥有该组,执行续费..."); + String err = ugm.renewGroup(targetName, cfg.name); + if (err != null) { + p.sendMessage("§c赠予续费失败: " + err); + } else { + p.sendMessage("§a§l赠予成功! §7已为 §e" + targetName + " §7续费用户组 §e" + displayName); + // 通知目标玩家 + Player target = plugin.getServer().getPlayerExact(targetName); + if (target != null) { + target.sendMessage("§a§l[赠予] §7玩家 §e" + p.getName() + " §7为你续费了用户组 §e" + displayName); + } + } + } else { + // 目标未加入 → 购买赠送 + p.sendMessage("§7正在为 §e" + targetName + " §7购买用户组 §e" + displayName + " §7..."); + String err = ugm.joinGroupByPrice(targetName, cfg.name); + if (err != null) { + p.sendMessage("§c赠予失败: " + err); + } else { + p.sendMessage("§a§l赠予成功! §7已为 §e" + targetName + " §7购买用户组 §e" + displayName); + Player target = plugin.getServer().getPlayerExact(targetName); + if (target != null) { + target.sendMessage("§a§l[赠予] §7玩家 §e" + p.getName() + " §7赠送了用户组 §e" + displayName + " §7给你!"); + } + } + } + } + + // ★ 赠予流程:记录赠送的组名 + private final Map pendingGiftGroup = new ConcurrentHashMap<>(); + + // ★ 自动续费偏好(per-player) + private final Map autoRenewCache = new ConcurrentHashMap<>(); + + private boolean getAutoRenew(String player, String group) { + String key = player + "|" + group; + if (autoRenewCache.containsKey(key)) return autoRenewCache.get(key); + // 从数据库读取 + boolean val = false; + try { + DatabaseManager dbMgr = plugin.getDb(); + if (dbMgr != null) { + val = dbMgr.getPlayerAutoRenew(player, group); + } + } catch (Exception ignored) {} + autoRenewCache.put(key, val); + return val; + } + + private void setAutoRenew(String player, String group, boolean value) { + String key = player + "|" + group; + autoRenewCache.put(key, value); + try { + DatabaseManager dbMgr = plugin.getDb(); + if (dbMgr != null) { + dbMgr.setPlayerAutoRenew(player, group, value); + } + } catch (Exception ignored) {} + } + + /** 从GUI物品名称中提取用户组名(去掉格式化前缀和后缀) */ + private String extractGroupNameFromItem(ItemStack item) { + if (item == null || !item.hasItemMeta()) return null; + ItemMeta meta = item.getItemMeta(); + if (meta == null || meta.getDisplayName() == null) return null; + String name = meta.getDisplayName(); + // 去掉所有§格式化代码 + name = name.replaceAll("§[0-9a-fk-orA-FK-OR]", ""); + // 去掉后缀 " (购买)" + name = name.replaceAll("\\s*\\(购买\\)$", "").trim(); + // 匹配已知组名 + UserGroupManager ugm = plugin.getUserGroup(); + if (ugm == null) return null; + for (UserGroupManager.UserGroupConfig cfg : ugm.getAllGroups()) { + String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; + if (name.equals(displayName) || name.equals(cfg.name)) { + return cfg.name; + } + } + return null; + } + private void fillBg(Inventory inv) { ItemStack glass = new ItemStack( Material.GRAY_STAINED_GLASS_PANE); diff --git a/src/main/java/Sdf1_login/Main.java b/src/main/java/Sdf1_login/Main.java index a45bfd8..34ab4b6 100644 --- a/src/main/java/Sdf1_login/Main.java +++ b/src/main/java/Sdf1_login/Main.java @@ -4542,30 +4542,27 @@ public class Main extends JavaPlugin } if (args.length == 0) { - // /group → 显示帮助 - p.sendMessage("§6§l用户组§7 命令列表:"); - p.sendMessage("§7────────────────────"); - p.sendMessage("§e/group buy <组名> §7- 付费加入用户组"); - p.sendMessage("§e/group renew <组名> §7- 续费用户组"); - p.sendMessage("§e/group info §7- 查看我的用户组"); - p.sendMessage("§7────────────────────"); - - // 显示可购买的用户组 - List allGroups = userGroupManager.getAllGroups(); - boolean hasBuyable = false; - for (UserGroupManager.UserGroupConfig cfg : allGroups) { - if (cfg.joinPrice > 0) { - if (!hasBuyable) { - p.sendMessage("§6可购买的用户组:"); - hasBuyable = true; + // /group → 打开用户组GUI + if (gui != null) { + gui.openUserGroup(p); + } else { + // 降级到文本帮助 + p.sendMessage("§6§l用户组§7 命令列表:"); + p.sendMessage("§7────────────────────"); + p.sendMessage("§e/group buy <组名> §7- 付费加入用户组"); + p.sendMessage("§e/group renew <组名> §7- 续费用户组"); + p.sendMessage("§e/group info §7- 查看我的用户组"); + p.sendMessage("§7────────────────────"); + List allGroups2 = userGroupManager.getAllGroups(); + boolean hasBuyable = false; + for (UserGroupManager.UserGroupConfig cfg : allGroups2) { + if (cfg.joinPrice > 0) { + if (!hasBuyable) { p.sendMessage("§6可购买的用户组:"); hasBuyable = true; } + String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; + p.sendMessage("§e • " + displayName + " §7- " + cfg.joinPrice + " 张债券"); } - String displayName = cfg.displayName.isEmpty() ? cfg.name : cfg.displayName; - p.sendMessage("§e • " + displayName + " §7- " + cfg.joinPrice + " 张债券 | 有效期 " + cfg.durationMinutes + " 分钟"); } } - if (!hasBuyable) { - p.sendMessage("§7暂无可购买的用户组"); - } return true; }