diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java b/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java index dc61408..883359f 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java @@ -27,500 +27,513 @@ import com.modnmetl.virtualrealty.model.plot.PlotSize; import com.modnmetl.virtualrealty.util.EnumUtils; import com.modnmetl.virtualrealty.util.MapUtils; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; + import lombok.SneakyThrows; public class CommandManager implements TabCompleter { - public static final HashMap, SortedSet> SUBCOMMANDS = new HashMap<>(); + public static final HashMap, SortedSet> SUBCOMMANDS = new HashMap<>(); + + public static void addSubCommand(String subCommand, Class mainCommandClass) { + if (subCommand == null || subCommand.isEmpty()) + return; + if (!SUBCOMMANDS.containsKey(mainCommandClass)) { + SUBCOMMANDS.put(mainCommandClass, new TreeSet<>()); + } + SUBCOMMANDS.get(mainCommandClass).add(subCommand); + String className = mainCommandClass.getPackage().getName() + ".subcommand." + + subCommand.replaceFirst(Character.toString(subCommand.toCharArray()[0]), + Character.toString(Character.toUpperCase(subCommand.toCharArray()[0]))) + + "SubCommand"; + Class subcommandClass; + try { + subcommandClass = VirtualRealty.getLoader().loadClass(className); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + String name = mainCommandClass.getPackage().getName().replaceAll("com.modnmetl.virtualrealty.commands.", "") + .toUpperCase(); + CommandRegistry.addSubCommandToRegistry(subcommandClass, CommandType.valueOf(name)); + } + + @SneakyThrows + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + List tabCompleter = new LinkedList<>(); + if (command.getName().equalsIgnoreCase("virtualrealty")) { + if (assertPermission(sender, VirtualRealtyCommand.COMMAND_PERMISSION.getName())) + return null; + Map vrplotAliases = VirtualRealty.getCommands().vrplotAliases; + if (args.length <= 1) { + for (String subcommand : vrplotAliases.values()) { + if (args[0].isEmpty()) { + tabCompleter.add(subcommand); + } else if (subcommand.startsWith(args[0])) { + tabCompleter.add(subcommand); + } + } + } + String subCommand = args[0].toLowerCase(); + String keyByValue = MapUtils.getKeyByValue(vrplotAliases, subCommand); + if (subCommand.isEmpty() || keyByValue == null) { + return tabCompleter; + } + switch (keyByValue.toUpperCase()) { + case "CREATE": { + if (assertPermission(sender, + VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) + return null; + if (args.length > 1) { + // Enum Hints (Sizes) + if (args.length == 2) { + for (PlotSize value : PlotSize.values()) { + if (value == PlotSize.CUSTOM) + continue; + if (args[1].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase().startsWith(args[1].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + } + boolean isNatural = Arrays.stream(args).anyMatch(s -> s.equalsIgnoreCase("--natural")); + args = Arrays.stream(args).filter(s1 -> !s1.equalsIgnoreCase("--natural")).toArray(String[]::new); + if (isNatural) + return null; + // Enum Hints (Materials) + if (args.length > 2) { + boolean predefinedValue = EnumUtils.isValidEnum(PlotSize.class, args[1].toUpperCase()); + PlotSize plotSize = predefinedValue ? PlotSize.valueOf(args[1].toUpperCase()) : PlotSize.CUSTOM; + if (plotSize != PlotSize.AREA) { + if (((predefinedValue && args.length < 5) + || (!predefinedValue && args.length > 4 && args.length < 7))) { + for (Material value : Material.values()) { + if (!value.isSolid()) + continue; + if (args[args.length - 1].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase() + .startsWith(args[args.length - 1].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + } + } else if (args.length < 6) { + switch (args.length) { + case 3: { + String length = String.valueOf(plotSize.getLength()); + if (args[args.length - 1].isEmpty()) { + tabCompleter.add(length.toLowerCase()); + } else if (length.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { + tabCompleter.add(length.toLowerCase()); + } + break; + } + case 4: { + String height = String.valueOf(plotSize.getHeight()); + if (args[args.length - 1].isEmpty()) { + tabCompleter.add(height.toLowerCase()); + } else if (height.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { + tabCompleter.add(height.toLowerCase()); + } + break; + } + case 5: { + String width = String.valueOf(plotSize.getWidth()); + if (args[args.length - 1].isEmpty()) { + tabCompleter.add(width.toLowerCase()); + } else if (width.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { + tabCompleter.add(width.toLowerCase()); + } + break; + } + } + } + } + } + return tabCompleter; + } + case "SET": { + if (assertPermission(sender, + VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) + return null; + if (args.length == 2) { + for (Plot plot : PlotManager.getInstance().getPlots()) { + if (args[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + } + return tabCompleter; + } + if (args.length == 3) { + List arguments = Arrays.asList("owner", "floor", "border", "expiry"); + for (String argument : arguments) { + if (args[2].isEmpty()) { + tabCompleter.add(argument.toLowerCase()); + } else if (argument.toLowerCase().startsWith(args[2].toLowerCase())) { + tabCompleter.add(argument.toLowerCase()); + } + } + return tabCompleter; + } + if (args.length == 4) { + switch (args[2].toUpperCase()) { + case "FLOOR": + case "BORDER": { + for (Material value : Material.values()) { + if (!value.isSolid()) + continue; + if (args[3].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase().startsWith(args[3].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + return tabCompleter; + } + case "OWNER": { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (args[3].isEmpty()) { + tabCompleter.add(onlinePlayer.getName()); + } else if (onlinePlayer.getName().toLowerCase().startsWith(args[3].toLowerCase())) { + tabCompleter.add(onlinePlayer.getName()); + } + } + return tabCompleter; + } + case "EXPIRY": { + String validFormat = "31/12/2999"; + String argument = args[3].toLowerCase(); + if (argument.isEmpty()) { + tabCompleter.add(validFormat); + } else { + String display = null; + String[] providedStrings = argument.split("/"); + if (providedStrings.length == 1) { + display = validFormat.substring(2); + } + if (providedStrings.length == 2) { + display = validFormat.substring(5); + } + if (providedStrings.length == 3 && providedStrings[2].length() < 4) { + display = validFormat.substring(6 + providedStrings[2].length()); + } + if (display != null) { + if (argument.length() <= validFormat.length()) { + tabCompleter.add(display); + } + } + } + return tabCompleter; + } + } + } + if (args.length == 5) { + if (args[2].equalsIgnoreCase("expiry")) { + String validFormat = "00:00"; + String argument = args[4].toLowerCase(); + if (argument.isEmpty()) { + tabCompleter.add(validFormat); + } else { + String display = null; + String[] providedStrings = argument.split(":"); + if (providedStrings.length == 1) { + display = validFormat.substring(2); + } + if (display != null) { + if (argument.length() <= validFormat.length()) { + tabCompleter.add(display); + } + } + } + return tabCompleter; + } + } + return tabCompleter; + } + case "ASSIGN": + case "UNASSIGN": { + if (assertPermission(sender, + VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) + return null; + if (args.length == 2) { + for (Plot plot : PlotManager.getInstance().getPlots()) { + if (args[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + } + return tabCompleter; + } + if (args.length == 3) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (args[2].isEmpty()) { + tabCompleter.add(onlinePlayer.getName()); + } else if (onlinePlayer.getName().toLowerCase().startsWith(args[2].toLowerCase())) { + tabCompleter.add(onlinePlayer.getName()); + } + } + return tabCompleter; + } + return tabCompleter; + } + case "INFO": + case "REMOVE": + case "TP": { + if (assertPermission(sender, + VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) + return null; + if (args.length == 2) { + for (Plot plot : PlotManager.getInstance().getPlots()) { + if (args[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + } + return tabCompleter; + } + } + case "ITEM": { + if (assertPermission(sender, + VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) + return null; + if (args.length > 1) { + boolean isNatural = Arrays.stream(args).anyMatch(s -> s.equalsIgnoreCase("--natural")); + args = Arrays.stream(args).filter(s1 -> !s1.equalsIgnoreCase("--natural")).toArray(String[]::new); + int backwardsArgs = 3 + (isNatural ? 2 : 0); + if (args.length == 2) { + for (PlotSize value : PlotSize.values()) { + if (args[1].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase().startsWith(args[1].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + } + if (args.length > 2) { + if (!EnumUtils.isValidEnum(PlotSize.class, args[1].toUpperCase())) + return null; + PlotSize plotSize = PlotSize.valueOf(args[1].toUpperCase()); + int length; + int height; + int width; + switch (plotSize) { + case AREA: + case CUSTOM: { + backwardsArgs = (isNatural ? 2 : 0); + if (args.length == 3 && args[2].isEmpty()) { + tabCompleter.add(String.valueOf(plotSize.getLength())); + return tabCompleter; + } + if (args.length == 4 && args[3].isEmpty()) { + tabCompleter.add(String.valueOf(plotSize.getHeight())); + return tabCompleter; + } + if (args.length == 5 && args[4].isEmpty()) { + tabCompleter.add(String.valueOf(plotSize.getWidth())); + return tabCompleter; + } + if (args.length > 5) { + length = Integer.parseInt(args[2]); + height = Integer.parseInt(args[3]); + width = Integer.parseInt(args[4]); + } + } + } + if (args.length == 6 - backwardsArgs) { + tabCompleter.add("default"); + for (Material value : Material.values()) { + if (!value.isSolid()) + continue; + if (args[5 - backwardsArgs].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase() + .startsWith(args[5 - backwardsArgs].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + } + if (args.length == 7 - backwardsArgs) { + tabCompleter.add("default"); + for (Material value : Material.values()) { + if (!value.isSolid()) + continue; + if (args[6 - backwardsArgs].isEmpty()) { + tabCompleter.add(value.name().toLowerCase()); + } else if (value.name().toLowerCase() + .startsWith(args[6 - backwardsArgs].toLowerCase())) { + tabCompleter.add(value.name().toLowerCase()); + } + } + } + if (args.length == 8 - backwardsArgs) { + if (args[7 - backwardsArgs].isEmpty()) { + tabCompleter.add("180"); + return tabCompleter; + } + } + if (args.length == 9 - backwardsArgs) { + if (args[8 - backwardsArgs].isEmpty()) { + tabCompleter.add("1"); + return tabCompleter; + } + } + if (args.length == 10 - backwardsArgs) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (args[9 - backwardsArgs].isEmpty()) { + tabCompleter.add(onlinePlayer.getName()); + } else if (onlinePlayer.getName().toLowerCase() + .startsWith(args[9 - backwardsArgs].toLowerCase())) { + tabCompleter.add(onlinePlayer.getName()); + } + } + } + } + } + } + } + return tabCompleter; + } else if (command.getName().equalsIgnoreCase("plot")) { + if (!(sender instanceof Player)) + return null; + Player player = ((Player) sender); + Map plotAliasesMap = VirtualRealty.getCommands().plotAliases.getAliasesMap(); + if (args.length <= 1) { + for (String subcommand : plotAliasesMap.values()) { + if (args[0].isEmpty()) { + tabCompleter.add(subcommand); + } else if (subcommand.startsWith(args[0])) { + tabCompleter.add(subcommand); + } + } + } + @NotNull + String[] finalArgs = args; + @NotNull + String[] finalArgs1 = args; + String subCommand = args[0].toLowerCase(); + String keyByValue = MapUtils.getKeyByValue(plotAliasesMap, subCommand); + if (subCommand.isEmpty() || keyByValue == null) { + return tabCompleter; + } + switch (keyByValue.toUpperCase()) { + case "ADD": { + if (args.length == 2) { + PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { + if (plot.getMember(player.getUniqueId()) != null && !plot.getMember(player.getUniqueId()) + .hasManagementPermission(ManagementPermission.ADD_MEMBER)) + return; + if (finalArgs[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + }); + return tabCompleter; + } + if (args.length == 3) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + if (onlinePlayer.getName().equals(player.getName())) + continue; + if (args[2].isEmpty()) { + tabCompleter.add(onlinePlayer.getName()); + } else if (onlinePlayer.getName().toLowerCase().startsWith(args[2].toLowerCase())) { + tabCompleter.add(onlinePlayer.getName()); + } + } + return tabCompleter; + } + break; + } + case "LEAVE": { + if (args.length == 2) { + String trim = finalArgs[1].trim(); + PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { + if (trim.isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(trim.toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + }); + } + return tabCompleter; + } + case "KICK": { + if (args.length == 2) { + PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { + if (plot.getMember(player.getUniqueId()) != null && !plot.getMember(player.getUniqueId()) + .hasManagementPermission(ManagementPermission.KICK_MEMBER)) + return; + if (finalArgs[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + }); + return tabCompleter; + } + if (args.length == 3) { + String arg = args[1]; + try { + Integer.parseInt(arg.trim()); + } catch (NumberFormatException ex) { + return tabCompleter; + } + + Plot plot = PlotManager.getInstance().getPlot(Integer.parseInt(arg)); + if (plot == null) + return null; + + for (OfflinePlayer offlinePlayer : plot.getPlayerMembers()) { + // Resolve name safely, including Floodgate / unknown profiles + String memberName = PlayerLookupUtil.getBestName(offlinePlayer); + if (memberName == null || memberName.isEmpty()) { + continue; // can’t tab-complete a nameless member + } - public static void addSubCommand(String subCommand, Class mainCommandClass) { - if (subCommand == null || subCommand.isEmpty()) - return; - if (!SUBCOMMANDS.containsKey(mainCommandClass)) { - SUBCOMMANDS.put(mainCommandClass, new TreeSet<>()); - } - SUBCOMMANDS.get(mainCommandClass).add(subCommand); - String className = mainCommandClass.getPackage().getName() + ".subcommand." - + subCommand.replaceFirst(Character.toString(subCommand.toCharArray()[0]), - Character.toString(Character.toUpperCase(subCommand.toCharArray()[0]))) - + "SubCommand"; - Class subcommandClass; - try { - subcommandClass = VirtualRealty.getLoader().loadClass(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - String name = mainCommandClass.getPackage().getName().replaceAll("com.modnmetl.virtualrealty.commands.", "") - .toUpperCase(); - CommandRegistry.addSubCommandToRegistry(subcommandClass, CommandType.valueOf(name)); - } + // Don’t suggest yourself + if (memberName.equalsIgnoreCase(player.getName())) { + continue; + } - @SneakyThrows - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, - @NotNull String[] args) { - List tabCompleter = new LinkedList<>(); - if (command.getName().equalsIgnoreCase("virtualrealty")) { - if (assertPermission(sender, VirtualRealtyCommand.COMMAND_PERMISSION.getName())) - return null; - Map vrplotAliases = VirtualRealty.getCommands().vrplotAliases; - if (args.length <= 1) { - for (String subcommand : vrplotAliases.values()) { - if (args[0].isEmpty()) { - tabCompleter.add(subcommand); - } else if (subcommand.startsWith(args[0])) { - tabCompleter.add(subcommand); - } - } - } - String subCommand = args[0].toLowerCase(); - String keyByValue = MapUtils.getKeyByValue(vrplotAliases, subCommand); - if (subCommand.isEmpty() || keyByValue == null) { - return tabCompleter; - } - switch (keyByValue.toUpperCase()) { - case "CREATE": { - if (assertPermission(sender, - VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) - return null; - if (args.length > 1) { - // Enum Hints (Sizes) - if (args.length == 2) { - for (PlotSize value : PlotSize.values()) { - if (value == PlotSize.CUSTOM) - continue; - if (args[1].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase().startsWith(args[1].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - } - boolean isNatural = Arrays.stream(args).anyMatch(s -> s.equalsIgnoreCase("--natural")); - args = Arrays.stream(args).filter(s1 -> !s1.equalsIgnoreCase("--natural")).toArray(String[]::new); - if (isNatural) - return null; - // Enum Hints (Materials) - if (args.length > 2) { - boolean predefinedValue = EnumUtils.isValidEnum(PlotSize.class, args[1].toUpperCase()); - PlotSize plotSize = predefinedValue ? PlotSize.valueOf(args[1].toUpperCase()) : PlotSize.CUSTOM; - if (plotSize != PlotSize.AREA) { - if (((predefinedValue && args.length < 5) - || (!predefinedValue && args.length > 4 && args.length < 7))) { - for (Material value : Material.values()) { - if (!value.isSolid()) - continue; - if (args[args.length - 1].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase() - .startsWith(args[args.length - 1].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - } - } else if (args.length < 6) { - switch (args.length) { - case 3: { - String length = String.valueOf(plotSize.getLength()); - if (args[args.length - 1].isEmpty()) { - tabCompleter.add(length.toLowerCase()); - } else if (length.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { - tabCompleter.add(length.toLowerCase()); - } - break; - } - case 4: { - String height = String.valueOf(plotSize.getHeight()); - if (args[args.length - 1].isEmpty()) { - tabCompleter.add(height.toLowerCase()); - } else if (height.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { - tabCompleter.add(height.toLowerCase()); - } - break; - } - case 5: { - String width = String.valueOf(plotSize.getWidth()); - if (args[args.length - 1].isEmpty()) { - tabCompleter.add(width.toLowerCase()); - } else if (width.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) { - tabCompleter.add(width.toLowerCase()); - } - break; - } - } - } - } - } - return tabCompleter; - } - case "SET": { - if (assertPermission(sender, - VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) - return null; - if (args.length == 2) { - for (Plot plot : PlotManager.getInstance().getPlots()) { - if (args[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - } - return tabCompleter; - } - if (args.length == 3) { - List arguments = Arrays.asList("owner", "floor", "border", "expiry"); - for (String argument : arguments) { - if (args[2].isEmpty()) { - tabCompleter.add(argument.toLowerCase()); - } else if (argument.toLowerCase().startsWith(args[2].toLowerCase())) { - tabCompleter.add(argument.toLowerCase()); - } - } - return tabCompleter; - } - if (args.length == 4) { - switch (args[2].toUpperCase()) { - case "FLOOR": - case "BORDER": { - for (Material value : Material.values()) { - if (!value.isSolid()) - continue; - if (args[3].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase().startsWith(args[3].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - return tabCompleter; - } - case "OWNER": { - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (args[3].isEmpty()) { - tabCompleter.add(onlinePlayer.getName()); - } else if (onlinePlayer.getName().toLowerCase().startsWith(args[3].toLowerCase())) { - tabCompleter.add(onlinePlayer.getName()); - } - } - return tabCompleter; - } - case "EXPIRY": { - String validFormat = "31/12/2999"; - String argument = args[3].toLowerCase(); - if (argument.isEmpty()) { - tabCompleter.add(validFormat); - } else { - String display = null; - String[] providedStrings = argument.split("/"); - if (providedStrings.length == 1) { - display = validFormat.substring(2); - } - if (providedStrings.length == 2) { - display = validFormat.substring(5); - } - if (providedStrings.length == 3 && providedStrings[2].length() < 4) { - display = validFormat.substring(6 + providedStrings[2].length()); - } - if (display != null) { - if (argument.length() <= validFormat.length()) { - tabCompleter.add(display); - } - } - } - return tabCompleter; - } - } - } - if (args.length == 5) { - if (args[2].equalsIgnoreCase("expiry")) { - String validFormat = "00:00"; - String argument = args[4].toLowerCase(); - if (argument.isEmpty()) { - tabCompleter.add(validFormat); - } else { - String display = null; - String[] providedStrings = argument.split(":"); - if (providedStrings.length == 1) { - display = validFormat.substring(2); - } - if (display != null) { - if (argument.length() <= validFormat.length()) { - tabCompleter.add(display); - } - } - } - return tabCompleter; - } - } - return tabCompleter; - } - case "ASSIGN": - case "UNASSIGN": { - if (assertPermission(sender, - VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) - return null; - if (args.length == 2) { - for (Plot plot : PlotManager.getInstance().getPlots()) { - if (args[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - } - return tabCompleter; - } - if (args.length == 3) { - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (args[2].isEmpty()) { - tabCompleter.add(onlinePlayer.getName()); - } else if (onlinePlayer.getName().toLowerCase().startsWith(args[2].toLowerCase())) { - tabCompleter.add(onlinePlayer.getName()); - } - } - return tabCompleter; - } - return tabCompleter; - } - case "INFO": - case "REMOVE": - case "TP": { - if (assertPermission(sender, - VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) - return null; - if (args.length == 2) { - for (Plot plot : PlotManager.getInstance().getPlots()) { - if (args[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(args[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - } - return tabCompleter; - } - } - case "ITEM": { - if (assertPermission(sender, - VirtualRealtyCommand.COMMAND_PERMISSION.getName() + "." + args[0].toLowerCase())) - return null; - if (args.length > 1) { - boolean isNatural = Arrays.stream(args).anyMatch(s -> s.equalsIgnoreCase("--natural")); - args = Arrays.stream(args).filter(s1 -> !s1.equalsIgnoreCase("--natural")).toArray(String[]::new); - int backwardsArgs = 3 + (isNatural ? 2 : 0); - if (args.length == 2) { - for (PlotSize value : PlotSize.values()) { - if (args[1].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase().startsWith(args[1].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - } - if (args.length > 2) { - if (!EnumUtils.isValidEnum(PlotSize.class, args[1].toUpperCase())) - return null; - PlotSize plotSize = PlotSize.valueOf(args[1].toUpperCase()); - int length; - int height; - int width; - switch (plotSize) { - case AREA: - case CUSTOM: { - backwardsArgs = (isNatural ? 2 : 0); - if (args.length == 3 && args[2].isEmpty()) { - tabCompleter.add(String.valueOf(plotSize.getLength())); - return tabCompleter; - } - if (args.length == 4 && args[3].isEmpty()) { - tabCompleter.add(String.valueOf(plotSize.getHeight())); - return tabCompleter; - } - if (args.length == 5 && args[4].isEmpty()) { - tabCompleter.add(String.valueOf(plotSize.getWidth())); - return tabCompleter; - } - if (args.length > 5) { - length = Integer.parseInt(args[2]); - height = Integer.parseInt(args[3]); - width = Integer.parseInt(args[4]); - } - } - } - if (args.length == 6 - backwardsArgs) { - tabCompleter.add("default"); - for (Material value : Material.values()) { - if (!value.isSolid()) - continue; - if (args[5 - backwardsArgs].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase() - .startsWith(args[5 - backwardsArgs].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - } - if (args.length == 7 - backwardsArgs) { - tabCompleter.add("default"); - for (Material value : Material.values()) { - if (!value.isSolid()) - continue; - if (args[6 - backwardsArgs].isEmpty()) { - tabCompleter.add(value.name().toLowerCase()); - } else if (value.name().toLowerCase() - .startsWith(args[6 - backwardsArgs].toLowerCase())) { - tabCompleter.add(value.name().toLowerCase()); - } - } - } - if (args.length == 8 - backwardsArgs) { - if (args[7 - backwardsArgs].isEmpty()) { - tabCompleter.add("180"); - return tabCompleter; - } - } - if (args.length == 9 - backwardsArgs) { - if (args[8 - backwardsArgs].isEmpty()) { - tabCompleter.add("1"); - return tabCompleter; - } - } - if (args.length == 10 - backwardsArgs) { - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (args[9 - backwardsArgs].isEmpty()) { - tabCompleter.add(onlinePlayer.getName()); - } else if (onlinePlayer.getName().toLowerCase() - .startsWith(args[9 - backwardsArgs].toLowerCase())) { - tabCompleter.add(onlinePlayer.getName()); - } - } - } - } - } - } - } - return tabCompleter; - } else if (command.getName().equalsIgnoreCase("plot")) { - if (!(sender instanceof Player)) - return null; - Player player = ((Player) sender); - Map plotAliasesMap = VirtualRealty.getCommands().plotAliases.getAliasesMap(); - if (args.length <= 1) { - for (String subcommand : plotAliasesMap.values()) { - if (args[0].isEmpty()) { - tabCompleter.add(subcommand); - } else if (subcommand.startsWith(args[0])) { - tabCompleter.add(subcommand); - } - } - } - @NotNull - String[] finalArgs = args; - @NotNull - String[] finalArgs1 = args; - String subCommand = args[0].toLowerCase(); - String keyByValue = MapUtils.getKeyByValue(plotAliasesMap, subCommand); - if (subCommand.isEmpty() || keyByValue == null) { - return tabCompleter; - } - switch (keyByValue.toUpperCase()) { - case "ADD": { - if (args.length == 2) { - PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { - if (plot.getMember(player.getUniqueId()) != null && !plot.getMember(player.getUniqueId()) - .hasManagementPermission(ManagementPermission.ADD_MEMBER)) - return; - if (finalArgs[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - }); - return tabCompleter; - } - if (args.length == 3) { - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - if (onlinePlayer.getName().equals(player.getName())) - continue; - if (args[2].isEmpty()) { - tabCompleter.add(onlinePlayer.getName()); - } else if (onlinePlayer.getName().toLowerCase().startsWith(args[2].toLowerCase())) { - tabCompleter.add(onlinePlayer.getName()); - } - } - return tabCompleter; - } - break; - } - case "LEAVE": { - if (args.length == 2) { - String trim = finalArgs[1].trim(); - PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { - if (trim.isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(trim.toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - }); - } - return tabCompleter; - } - case "KICK": { - if (args.length == 2) { - PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { - if (plot.getMember(player.getUniqueId()) != null && !plot.getMember(player.getUniqueId()) - .hasManagementPermission(ManagementPermission.KICK_MEMBER)) - return; - if (finalArgs[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - }); - return tabCompleter; - } - if (args.length == 3) { - String arg = args[1]; - try { - Integer.parseInt(arg.trim()); - } catch (NumberFormatException e) { - return tabCompleter; - } - Plot plot = PlotManager.getInstance().getPlot(Integer.parseInt(arg)); - if (plot == null) - return null; - for (OfflinePlayer offlinePlayer : plot.getPlayerMembers()) { - if (Objects.equals(offlinePlayer.getName(), player.getName())) - continue; - if (args[2].isEmpty()) { - tabCompleter.add(offlinePlayer.getName()); - } else if (offlinePlayer.getName().toLowerCase().startsWith(args[2].toLowerCase())) { - tabCompleter.add(offlinePlayer.getName()); - } - } - return tabCompleter; - } - break; - } - case "TP": { - if (args.length == 2) { - PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { - if (finalArgs1[1].isEmpty()) { - tabCompleter.add(String.valueOf(plot.getID())); - } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs1[1].toLowerCase())) { - tabCompleter.add(String.valueOf(plot.getID())); - } - }); - return tabCompleter; - } - break; - } - } - return tabCompleter; - } - return null; - } + if (args[2].isEmpty()) { + tabCompleter.add(memberName); + } else if (memberName.toLowerCase().startsWith(args[2].toLowerCase())) { + tabCompleter.add(memberName); + } + } + return tabCompleter; + } + break; + } + case "TP": { + if (args.length == 2) { + PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { + if (finalArgs1[1].isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(finalArgs1[1].toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + }); + return tabCompleter; + } + break; + } + } + return tabCompleter; + } + return null; + } - public boolean assertPermission(CommandSender sender, String permission) { - return !sender.hasPermission(permission); - } + public boolean assertPermission(CommandSender sender, String permission) { + return !sender.hasPermission(permission); + } } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/AddSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/AddSubCommand.java index 45fab5c..62a34a7 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/AddSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/AddSubCommand.java @@ -19,93 +19,132 @@ import com.modnmetl.virtualrealty.model.permission.ManagementPermission; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.plot.PlotMember; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; public class AddSubCommand extends SubCommand { - public static LinkedList HELP = new LinkedList<>(); - - static { - HELP.add(" "); - HELP.add(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»"); - HELP.add(" §a/plot %command% §8<§7plot§8> §8<§7player§8>"); - } - - public AddSubCommand() { - } - - public AddSubCommand(CommandSender sender, Command command, String label, String[] args) - throws FailedCommandException { - super(sender, command, label, args, false, HELP); - } - - @Override - public void exec(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { - assertPlayer(); - Player player = ((Player) sender); - if (args.length < 3) { - printHelp(CommandType.PLOT); - return; - } - int plotID; - try { - plotID = Integer.parseInt(args[1]); - } catch (IllegalArgumentException e) { - ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(player); - return; - } - - Player playerToAdd = Bukkit.getPlayer(args[2]); - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(args[2]); - - if (playerToAdd != null && offlinePlayer.getFirstPlayed() == 0) { - ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(player); - return; - } - - UUID toAdd = offlinePlayer.getUniqueId(); - String name = offlinePlayer.getName(); - if (playerToAdd != null) { - toAdd = playerToAdd.getUniqueId(); - name = playerToAdd.getName(); - } - Plot plot = PlotManager.getInstance().getPlot(plotID); - if (plot == null) { - ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); - return; - } - if (!plot.hasMembershipAccess(player.getUniqueId())) { - ChatMessage.of(VirtualRealty.getMessages().notYourPlot).sendWithPrefix(sender); - return; - } - PlotMember plotMember = plot.getMember(player.getUniqueId()); - if (plotMember != null) { - if (!plotMember.hasManagementPermission(ManagementPermission.ADD_MEMBER)) { - ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(sender); - return; - } - } else { - if (!plot.getOwnedBy().equals(player.getUniqueId())) { - ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(sender); - return; - } - } - if (plot.getOwnedUntilDate().isBefore(LocalDateTime.now())) { - ChatMessage.of(VirtualRealty.getMessages().ownershipExpired).sendWithPrefix(sender); - return; - } - if (plot.getOwnedBy().equals(toAdd)) { - boolean equals = plot.getOwnedBy().equals(player.getUniqueId()); - ChatMessage.of( - equals ? VirtualRealty.getMessages().cantAddYourself : VirtualRealty.getMessages().alreadyInMembers) - .sendWithPrefix(sender); - return; - } - if (plot.getMember(toAdd) != null) { - ChatMessage.of(VirtualRealty.getMessages().alreadyInMembers).sendWithPrefix(sender); - return; - } - plot.addMember(toAdd); - ChatMessage.of(VirtualRealty.getMessages().playerAdd.replaceAll("%player%", name)).sendWithPrefix(sender); - } + public static LinkedList HELP = new LinkedList<>(); + static { + HELP.add(" "); + HELP.add(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»"); + HELP.add(" §a/plot %command% §8<§7plot§8> §8<§7player§8>"); + } + + public AddSubCommand() {} + + public AddSubCommand(CommandSender sender, Command command, String label, String[] args) + throws FailedCommandException { + super(sender, command, label, args, false, HELP); + } + + @Override + public void exec(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { + assertPlayer(); + Player player = (Player) sender; + + if (args.length < 3) { + printHelp(CommandType.PLOT); + return; + } + + // Parse plot ID safely + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (Exception ex) { + ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(player); + return; + } + + String targetArg = args[2]; + + // Try online first + Player online = Bukkit.getPlayer(targetArg); + UUID targetUUID; + String displayName; + + if (online != null) { + // Cleanest case — real online player + targetUUID = online.getUniqueId(); + displayName = online.getName(); + } else { + // Offline or Floodgate, or unknown/uncached + OfflinePlayer offline = Bukkit.getOfflinePlayer(targetArg); + targetUUID = offline.getUniqueId(); + + if (targetUUID == null) { + ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(player); + return; + } + + // Resolve a SAFE display name + displayName = PlayerLookupUtil.getBestName(offline); + + if (displayName == null || displayName.isEmpty()) { + // Fallback: use what the player typed, or short UUID + if (!targetArg.isEmpty()) { + displayName = targetArg; + } else { + displayName = targetUUID.toString().substring(0, 8); + } + } + } + + // Fetch plot + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(player); + return; + } + + // Access check + if (!plot.hasMembershipAccess(player.getUniqueId())) { + ChatMessage.of(VirtualRealty.getMessages().notYourPlot).sendWithPrefix(player); + return; + } + + PlotMember memberSender = plot.getMember(player.getUniqueId()); + if (memberSender != null) { + if (!memberSender.hasManagementPermission(ManagementPermission.ADD_MEMBER)) { + ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(player); + return; + } + } else { + if (!plot.getOwnedBy().equals(player.getUniqueId())) { + ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(player); + return; + } + } + + // Ownership time check + if (plot.getOwnedUntilDate().isBefore(LocalDateTime.now())) { + ChatMessage.of(VirtualRealty.getMessages().ownershipExpired).sendWithPrefix(player); + return; + } + + // Cannot add yourself if you're owner + if (plot.getOwnedBy().equals(targetUUID)) { + boolean equals = plot.getOwnedBy().equals(player.getUniqueId()); + ChatMessage msg = ChatMessage.of( + equals ? VirtualRealty.getMessages().cantAddYourself : VirtualRealty.getMessages().alreadyInMembers + ); + msg.sendWithPrefix(player); + return; + } + + // Already a member? + if (plot.getMember(targetUUID) != null) { + ChatMessage.of(VirtualRealty.getMessages().alreadyInMembers).sendWithPrefix(player); + return; + } + + // Add the member + plot.addMember(targetUUID); + + // Send safe success message + ChatMessage.of( + VirtualRealty.getMessages().playerAdd.replace("%player%", displayName) + ).sendWithPrefix(player); + } } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/InfoSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/InfoSubCommand.java index 00d4312..cb8c127 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/InfoSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/InfoSubCommand.java @@ -6,6 +6,7 @@ import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -27,33 +28,52 @@ public InfoSubCommand(CommandSender sender, Command command, String label, Strin @Override public void exec(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { assertPlayer(); - Player player = ((Player) sender); + Player player = (Player) sender; + Plot plot = PlotManager.getInstance().getPlot(player.getLocation()); if (plot == null) { sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().notStandingOnPlot); return; } + printInfo(sender, plot); } private void printInfo(CommandSender sender, Plot plot) { LocalDateTime localDateTime = plot.getOwnedUntilDate(); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + ChatMessage.of(" ").send(sender); ChatMessage.of(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»").send(sender); ChatMessage.of(" §7Plot ID §8§l‣ §f" + plot.getID()).send(sender); - ChatMessage.of(" §7Owned By §8§l‣ §a" + (plot.getOwnedBy() != null ? (Bukkit.getOfflinePlayer(plot.getOwnedBy()).isOnline() ? "§a" : "§c") + Bukkit.getOfflinePlayer(plot.getOwnedBy()).getName() : "§cAvailable")).send(sender); - if (plot.getMembers().size() != 0) { + + // OWNER display (Floodgate/Offline-safe) + String ownerDisplay; + if (plot.getOwnedBy() == null) { + ownerDisplay = "§cAvailable"; + } else { + OfflinePlayer owner = Bukkit.getOfflinePlayer(plot.getOwnedBy()); + boolean online = owner.isOnline(); + String name = PlayerLookupUtil.getBestName(owner); + ownerDisplay = (online ? "§a" : "§c") + name; + } + ChatMessage.of(" §7Owned By §8§l‣ " + ownerDisplay).send(sender); + + // MEMBERS section + if (!plot.getMembers().isEmpty()) { ChatMessage.of(" §7Members §8§l↴").send(sender); - for (OfflinePlayer offlinePlayer : plot.getPlayerMembers()) { - ChatMessage.of(" §8§l⁍ §" + (offlinePlayer.isOnline() ? "a" : "c") + offlinePlayer.getName()).send(sender); + + for (OfflinePlayer member : plot.getPlayerMembers()) { + boolean online = member.isOnline(); + String name = PlayerLookupUtil.getBestName(member); + ChatMessage.of(" §8§l⁍ §" + (online ? "a" : "c") + name).send(sender); } } + ChatMessage.of(" §7Owned Until §8§l‣ §f" + dateTimeFormatter.format(localDateTime)).send(sender); ChatMessage.of(" §7Size §8§l‣ §f" + plot.getPlotSize()).send(sender); ChatMessage.of(" §7Length §8§l‣ §f" + plot.getLength()).send(sender); ChatMessage.of(" §7Height §8§l‣ §f" + plot.getHeight()).send(sender); ChatMessage.of(" §7Width §8§l‣ §f" + plot.getWidth()).send(sender); } - } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/KickSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/KickSubCommand.java index ec9091a..70cdec5 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/KickSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/KickSubCommand.java @@ -2,6 +2,7 @@ import java.time.LocalDateTime; import java.util.LinkedList; +import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; @@ -18,6 +19,7 @@ import com.modnmetl.virtualrealty.model.permission.ManagementPermission; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.plot.PlotMember; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; public class KickSubCommand extends SubCommand { @@ -38,11 +40,14 @@ public KickSubCommand(CommandSender sender, Command command, String label, Strin @Override public void exec(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { assertPlayer(); - Player player = ((Player) sender); + Player player = (Player) sender; + if (args.length < 3) { printHelp(CommandType.PLOT); return; } + + // Parse plot ID int plotID; try { plotID = Integer.parseInt(args[1]); @@ -50,48 +55,78 @@ public void exec(CommandSender sender, Command command, String label, String[] a ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(sender); return; } - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(args[2]); - if (offlinePlayer.getName() == null) { - ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(sender); - return; - } + + // Resolve target player by name (works for Java + Floodgate names) + String targetNameArg = args[2]; + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(targetNameArg); + UUID targetUUID = offlinePlayer.getUniqueId(); + Plot plot = PlotManager.getInstance().getPlot(plotID); if (plot == null) { ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); return; } + + // Plot must be owned + UUID ownerId = plot.getOwnedBy(); + if (ownerId == null) { + ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); + return; + } + + // Sender must have access to this plot if (!plot.hasMembershipAccess(player.getUniqueId())) { ChatMessage.of(VirtualRealty.getMessages().notYourPlot).sendWithPrefix(sender); return; } - PlotMember plotMember = plot.getMember(player.getUniqueId()); - if (plotMember != null) { - if (!plotMember.hasManagementPermission(ManagementPermission.KICK_MEMBER)) { + + // Check management permissions (either owner or member with KICK_MEMBER) + PlotMember senderMember = plot.getMember(player.getUniqueId()); + if (senderMember != null) { + if (!senderMember.hasManagementPermission(ManagementPermission.KICK_MEMBER)) { ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(sender); return; } } else { - if (!plot.getOwnedBy().equals(player.getUniqueId())) { + if (!ownerId.equals(player.getUniqueId())) { ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(sender); return; } } + + // Ownership expired? if (plot.getOwnedUntilDate().isBefore(LocalDateTime.now())) { ChatMessage.of(VirtualRealty.getMessages().ownershipExpired).sendWithPrefix(sender); return; } - if (plot.getOwnedBy().equals(offlinePlayer.getUniqueId())) { - boolean equals = plot.getOwnedBy().equals(player.getUniqueId()); - ChatMessage.of(equals ? VirtualRealty.getMessages().cantKickYourself : VirtualRealty.getMessages().cantKickOwner).sendWithPrefix(sender); + + // Can't kick owner (or yourself if you are the owner) + if (ownerId.equals(targetUUID)) { + boolean equals = ownerId.equals(player.getUniqueId()); + ChatMessage.of(equals + ? VirtualRealty.getMessages().cantKickYourself + : VirtualRealty.getMessages().cantKickOwner).sendWithPrefix(sender); return; } - PlotMember member = plot.getMember(offlinePlayer.getUniqueId()); + + // Get member by UUID; if not present, report not found + PlotMember member = plot.getMember(targetUUID); if (member == null) { ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(sender); return; } + + // Remove member and send confirmation message plot.removeMember(member); - ChatMessage.of(VirtualRealty.getMessages().playerKick.replaceAll("%player%", offlinePlayer.getName())).sendWithPrefix(sender); + + String displayName = PlayerLookupUtil.getBestName(offlinePlayer); + if (displayName == null || displayName.isEmpty()) { + displayName = targetNameArg; + } + + ChatMessage.of( + VirtualRealty.getMessages().playerKick.replaceAll("%player%", displayName) + ).sendWithPrefix(sender); } } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/AssignSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/AssignSubCommand.java index 50b8c79..8854ab8 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/AssignSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/AssignSubCommand.java @@ -6,8 +6,9 @@ import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.model.other.CommandType; import com.modnmetl.virtualrealty.model.plot.Plot; -import com.modnmetl.virtualrealty.util.UUIDUtils; import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; +import com.modnmetl.virtualrealty.util.UUIDUtils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -33,41 +34,57 @@ public AssignSubCommand() {} public AssignSubCommand(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { super(sender, command, label, args, HELP); } - + @Override public void exec(CommandSender sender, Command command, String label, String[] args) throws Exception { assertPermission(); - if (args.length < 2) { + + // Need: /vrplot assign + if (args.length < 3) { printHelp(CommandType.VRPLOT); return; } + + // Parse plot ID int plotID; - OfflinePlayer offlinePlayer; try { plotID = Integer.parseInt(args[1]); } catch (IllegalArgumentException e) { ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(sender); return; } + + // Resolve target player (by UUID or name) + String targetArg = args[2]; + OfflinePlayer offlinePlayer; try { - if (UUIDUtils.isValidUUID(args[2])) { - offlinePlayer = Bukkit.getOfflinePlayer(UUID.fromString(args[2])); + if (UUIDUtils.isValidUUID(targetArg)) { + UUID uuid = UUID.fromString(targetArg); + offlinePlayer = Bukkit.getOfflinePlayer(uuid); } else { - offlinePlayer = Bukkit.getOfflinePlayer(args[2]); - } - if (offlinePlayer.getName() == null) { - ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(sender); - return; + offlinePlayer = Bukkit.getOfflinePlayer(targetArg); } - } catch (NullPointerException e) { + } catch (Exception ex) { + // Very defensive: if anything goes wrong resolving the player, treat as "not found" ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(sender); return; } + + // If Bukkit somehow gave us a null name, we still allow the assignment, but + // we will fall back to the argument or a short UUID for the display name. + UUID targetUUID = offlinePlayer.getUniqueId(); + if (targetUUID == null) { + ChatMessage.of(VirtualRealty.getMessages().playerNotFoundWithUsername).sendWithPrefix(sender); + return; + } + Plot plot = PlotManager.getInstance().getPlot(plotID); if (plot == null) { ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); return; } + + // Record who assigned it if (sender instanceof Player) { plot.setAssignedBy(((Player) sender).getUniqueId().toString()); } else if (sender instanceof ConsoleCommandSender) { @@ -75,10 +92,27 @@ public void exec(CommandSender sender, Command command, String label, String[] a } else { plot.setAssignedBy("SHOP_PURCHASE"); } - plot.setOwnedBy(offlinePlayer.getUniqueId()); - String text = VirtualRealty.getMessages().assignedToBy.replaceAll("%assigned_to%", offlinePlayer.getName()).replaceAll("%assigned_by%", sender.getName()); + + // Set ownership by UUID (works for Java + Floodgate) + plot.setOwnedBy(targetUUID); + + // Get a safe display name for messages + String displayName = PlayerLookupUtil.getBestName(offlinePlayer); + if (displayName == null || displayName.isEmpty()) { + // Fall back to what the admin typed, or a short UUID + if (!targetArg.isEmpty()) { + displayName = targetArg; + } else { + displayName = targetUUID.toString().substring(0, 8); + } + } + + String text = VirtualRealty.getMessages().assignedToBy + .replaceAll("%assigned_to%", displayName) + .replaceAll("%assigned_by%", sender.getName()); + ChatMessage.of(text).sendWithPrefix(sender); plot.update(); } - + } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/InfoSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/InfoSubCommand.java index 0c0bfff..270f83d 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/InfoSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/InfoSubCommand.java @@ -6,6 +6,7 @@ import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -21,16 +22,20 @@ public class InfoSubCommand extends SubCommand { public InfoSubCommand() {} - public InfoSubCommand(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { + public InfoSubCommand(CommandSender sender, Command command, String label, String[] args) + throws FailedCommandException { super(sender, command, label, args, new LinkedList<>()); } @Override public void exec(CommandSender sender, Command command, String label, String[] args) throws Exception { assertPermission(); + + // /vrplot info OR /vrplot info if (args.length < 2) { assertPlayer(); - Plot plot = PlotManager.getInstance().getPlot(((Player) sender).getLocation()); + Player player = (Player) sender; + Plot plot = PlotManager.getInstance().getPlot(player.getLocation()); if (plot == null) { ChatMessage.of(VirtualRealty.getMessages().notStandingOnPlot).sendWithPrefix(sender); return; @@ -38,6 +43,7 @@ public void exec(CommandSender sender, Command command, String label, String[] a printInfo(sender, plot); return; } + int plotID; try { plotID = Integer.parseInt(args[1]); @@ -45,69 +51,110 @@ public void exec(CommandSender sender, Command command, String label, String[] a ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(sender); return; } + if (PlotManager.getInstance().getPlots().isEmpty()) { ChatMessage.of(VirtualRealty.getMessages().noPlots).sendWithPrefix(sender); return; } + if (plotID < PlotManager.getInstance().getPlotMinID()) { - String message = VirtualRealty.getMessages().minPlotID.replaceAll("%min_id%", String.valueOf(PlotManager.getInstance().getPlotMinID())); - ChatMessage.of(message).sendWithPrefix(sender); + String msg = VirtualRealty.getMessages().minPlotID + .replace("%min_id%", String.valueOf(PlotManager.getInstance().getPlotMinID())); + ChatMessage.of(msg).sendWithPrefix(sender); return; } + if (plotID > PlotManager.getInstance().getPlotMaxID()) { - String message = VirtualRealty.getMessages().maxPlotID.replaceAll("%max_id%", String.valueOf(PlotManager.getInstance().getPlotMaxID())); - ChatMessage.of(message).sendWithPrefix(sender); + String msg = VirtualRealty.getMessages().maxPlotID + .replace("%max_id%", String.valueOf(PlotManager.getInstance().getPlotMaxID())); + ChatMessage.of(msg).sendWithPrefix(sender); return; } + Plot plot = PlotManager.getInstance().getPlot(plotID); if (plot == null) { ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); return; } + printInfo(sender, plot); } private void printInfo(CommandSender sender, Plot plot) { - LocalDateTime localDateTime = plot.getOwnedUntilDate(); - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); + + LocalDateTime until = plot.getOwnedUntilDate(); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss"); + + // Assigned By String assignedBy = VirtualRealty.getMessages().notAssigned; + if (plot.getAssignedBy() != null) { - switch (plot.getAssignedBy().toUpperCase()) { - case "CONSOLE": { + String assignedRaw = plot.getAssignedBy(); + + switch (assignedRaw.toUpperCase()) { + case "CONSOLE": assignedBy = VirtualRealty.getMessages().assignedByConsole; break; - } - case "SHOP_PURCHASE": { + + case "SHOP_PURCHASE": assignedBy = VirtualRealty.getMessages().assignedByShopPurchase; break; - } - default: { - OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(UUID.fromString(plot.getAssignedBy())); - assignedBy = (offlinePlayer.isOnline() ? "§a" : "§c") + offlinePlayer.getName(); - } + + default: + // UUID of player who assigned it + try { + UUID assignerUUID = UUID.fromString(assignedRaw); + OfflinePlayer p = Bukkit.getOfflinePlayer(assignerUUID); + boolean online = p.isOnline(); + String name = PlayerLookupUtil.getBestName(p); + assignedBy = (online ? "§a" : "§c") + name; + } catch (Exception ignored) { + assignedBy = assignedRaw; + } + break; } } + + // Owner display + String ownerDisplay; + if (plot.getOwnedBy() == null) { + ownerDisplay = "§cAvailable"; + } else { + UUID ownerUUID = plot.getOwnedBy(); + OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerUUID); + boolean online = owner.isOnline(); + String name = PlayerLookupUtil.getBestName(owner); + ownerDisplay = (online ? "§a" : "§c") + name; + } + ChatMessage.of(" ").sendWithPrefix(sender); - ChatMessage.of(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»").sendWithPrefix(sender); + ChatMessage.of(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»") + .sendWithPrefix(sender); + ChatMessage.of(" §7Plot ID §8§l‣ §f" + plot.getID()).sendWithPrefix(sender); - ChatMessage.of(" §7Owned By §8§l‣ §a" + (plot.getOwnedBy() != null ? (Bukkit.getOfflinePlayer(plot.getOwnedBy()).isOnline() ? "§a" : "§c") + Bukkit.getOfflinePlayer(plot.getOwnedBy()).getName() : "§cAvailable")).sendWithPrefix(sender); - if (plot.getMembers().size() != 0) { + ChatMessage.of(" §7Owned By §8§l‣ " + ownerDisplay).sendWithPrefix(sender); + + // Members + if (!plot.getMembers().isEmpty()) { ChatMessage.of(" §7Members §8§l↴").send(sender); - for (OfflinePlayer offlinePlayer : plot.getPlayerMembers()) { - ChatMessage.of(" §8§l⁍ §" + (offlinePlayer.isOnline() ? "a" : "c") + offlinePlayer.getName()).send(sender); + + for (OfflinePlayer member : plot.getPlayerMembers()) { + boolean online = member.isOnline(); + String name = PlayerLookupUtil.getBestName(member); + ChatMessage.of(" §8§l⁍ §" + (online ? "a" : "c") + name).send(sender); } } + ChatMessage.of(" §7Assigned By §8§l‣ §a" + assignedBy).send(sender); - ChatMessage.of(" §7Owned Until §8§l‣ §f" + dateTimeFormatter.format(localDateTime)).send(sender); + ChatMessage.of(" §7Owned Until §8§l‣ §f" + fmt.format(until)).send(sender); ChatMessage.of(" §7Size §8§l‣ §f" + plot.getPlotSize()).send(sender); ChatMessage.of(" §7Length §8§l‣ §f" + plot.getLength()).send(sender); ChatMessage.of(" §7Height §8§l‣ §f" + plot.getHeight()).send(sender); ChatMessage.of(" §7Width §8§l‣ §f" + plot.getWidth()).send(sender); ChatMessage.of(" §7Floor Material §8§l‣ §f" + plot.getFloorMaterialName()).send(sender); ChatMessage.of(" §7Border Material §8§l‣ §f" + plot.getBorderMaterialName()).send(sender); - ChatMessage.of(" §7Pos 1 §8( §7X §8| §7Y §8| §7Z §8) §8§l‣ §f" + plot.getBottomLeftCorner().toString()).send(sender); - ChatMessage.of(" §7Pos 2 §8( §7X §8| §7Y §8| §7Z §8) §8§l‣ §f" + plot.getTopRightCorner().toString()).send(sender); + ChatMessage.of(" §7Pos 1 §8( §7X §8| §7Y §8| §7Z §8) §8§l‣ §f" + plot.getBottomLeftCorner()).send(sender); + ChatMessage.of(" §7Pos 2 §8( §7X §8| §7Y §8| §7Z §8) §8§l‣ §f" + plot.getTopRightCorner()).send(sender); ChatMessage.of(" §7Created Direction §8§l‣ §f" + plot.getCreatedDirection().name()).send(sender); } - } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/SetSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/SetSubCommand.java index c2c86d1..f5cb82e 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/SetSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/vrplot/subcommand/SetSubCommand.java @@ -19,226 +19,258 @@ import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.model.other.CommandType; import com.modnmetl.virtualrealty.model.plot.Plot; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; import com.modnmetl.virtualrealty.util.UUIDUtils; public class SetSubCommand extends SubCommand { - public static LinkedList HELP = new LinkedList<>(); - - static { - HELP.add(" "); - HELP.add(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»"); - HELP.add(" §a/vrplot %command% §8<§7plot§8> §aowner §8<§7username§8>"); - HELP.add(" §a/vrplot %command% §8<§7plot§8> §afloor §8<§7material§8>"); - HELP.add(" §a/vrplot %command% §8<§7plot§8> §aborder §8<§7material§8>"); - HELP.add(" §a/vrplot %command% §8<§7plot§8> §aexpiry §8<§7dd/mm/YYYY§8> §8<§7HH:mm (optional)§8>"); - } - - public SetSubCommand() { - } - - public SetSubCommand(CommandSender sender, Command command, String label, String[] args) - throws FailedCommandException { - super(sender, command, label, args, HELP); - } - - @Override - public void exec(CommandSender sender, Command command, String label, String[] args) throws Exception { - assertPermission(); - if (args.length < 3) { - printHelp(CommandType.VRPLOT); - return; - } - switch (args[2].toUpperCase()) { - case "OWNER": { - assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); - if (args.length < 4) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyUsername); - return; - } - int plotID; - OfflinePlayer offlinePlayer; - try { - plotID = Integer.parseInt(args[1]); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); - return; - } - try { - if (UUIDUtils.isValidUUID(args[3])) { - offlinePlayer = Bukkit.getOfflinePlayer(UUID.fromString(args[3])); - } else { - offlinePlayer = Bukkit.getOfflinePlayer(args[3]); - } - if (offlinePlayer.getName() == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().playerNotFoundWithUsername); - return; - } - } catch (NullPointerException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().playerNotFoundWithUsername); - return; - } - Plot plot = PlotManager.getInstance().getPlot(plotID); - if (plot == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); - return; - } - if (args.length >= 5) { - String dateFormat = args[4]; - String timeFormat; - int year; - int month; - int dayOfMonth; - int hour = 0; - int minute = 0; - LocalDateTime localDateTime; - try { - year = Integer.parseInt(dateFormat.split("/")[2]); - month = Integer.parseInt(dateFormat.split("/")[1]); - dayOfMonth = Integer.parseInt(dateFormat.split("/")[0]); - if (args.length >= 6) { - timeFormat = args[5]; - hour = Integer.parseInt(timeFormat.split(":")[0]); - minute = Integer.parseInt(timeFormat.split(":")[1]); - } - localDateTime = LocalDateTime.of(year, month, dayOfMonth, hour, minute); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().invalidDateProvided); - return; - } - plot.setOwnedUntilDate(localDateTime); - } - if (sender instanceof RemoteConsoleCommandSender && args.length >= 7 - && args[6].equalsIgnoreCase("assign")) { - plot.setAssignedBy("SHOP_PURCHASE"); - } - plot.setOwnedBy(offlinePlayer.getUniqueId()); - sender.sendMessage(VirtualRealty.PREFIX - + VirtualRealty.getMessages().assignedTo.replaceAll("%assigned_to%", offlinePlayer.getName())); - plot.update(); - return; - } - case "FLOOR": { - assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); - if (args.length < 4) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyMaterialName); - return; - } - int plotID; - try { - plotID = Integer.parseInt(args[1]); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); - return; - } - Material material; - try { - material = Material.matchMaterial(args[3].split(":")[0].toUpperCase()); - if (material == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); - return; - } - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); - return; - } - Plot plot = PlotManager.getInstance().getPlot(plotID); - if (plot == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); - return; - } - - plot.setFloorMaterial(material); - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().newFloorMaterialSet); - plot.update(); - return; - } - case "BORDER": { - assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); - if (args.length < 4) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyMaterialName); - return; - } - int plotID; - try { - plotID = Integer.parseInt(args[1]); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); - return; - } - Material material; - try { - material = Material.getMaterial(args[3].split(":")[0].toUpperCase()); - if (material == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); - return; - } - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); - return; - } - Plot plot = PlotManager.getInstance().getPlot(plotID); - if (plot == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); - return; - } - - plot.setBorderMaterial(material); - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().newBorderMaterialSet); - plot.update(); - return; - } - case "EXPIRY": { - assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); - if (args.length < 4) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyExpiryDate); - return; - } - int plotID; - try { - plotID = Integer.parseInt(args[1]); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); - return; - } - String dateFormat = args[3]; - String timeFormat; - int year; - int month; - int dayOfMonth; - int hour = 0; - int minute = 0; - LocalDateTime localDateTime; - try { - year = Integer.parseInt(dateFormat.split("/")[2]); - month = Integer.parseInt(dateFormat.split("/")[1]); - dayOfMonth = Integer.parseInt(dateFormat.split("/")[0]); - if (args.length == 5) { - timeFormat = args[4]; - hour = Integer.parseInt(timeFormat.split(":")[0]); - minute = Integer.parseInt(timeFormat.split(":")[1]); - } - localDateTime = LocalDateTime.of(year, month, dayOfMonth, hour, minute); - } catch (IllegalArgumentException e) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().invalidDateProvided); - return; - } - Plot plot = PlotManager.getInstance().getPlot(plotID); - if (plot == null) { - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); - return; - } - plot.setOwnedUntilDate(localDateTime); - sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().ownedUntilUpdated); - plot.update(); - return; - } - default: { - for (String helpMessage : HELP) { - sender.sendMessage(helpMessage); - } - } - } - } + public static LinkedList HELP = new LinkedList<>(); + + static { + HELP.add(" "); + HELP.add(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»"); + HELP.add(" §a/vrplot %command% §8<§7plot§8> §aowner §8<§7username§8>"); + HELP.add(" §a/vrplot %command% §8<§7plot§8> §afloor §8<§7material§8>"); + HELP.add(" §a/vrplot %command% §8<§7plot§8> §aborder §8<§7material§8>"); + HELP.add(" §a/vrplot %command% §8<§7plot§8> §aexpiry §8<§7dd/mm/YYYY§8> §8<§7HH:mm (optional)§8>"); + } + + public SetSubCommand() { + } + + public SetSubCommand(CommandSender sender, Command command, String label, String[] args) + throws FailedCommandException { + super(sender, command, label, args, HELP); + } + + @Override + public void exec(CommandSender sender, Command command, String label, String[] args) throws Exception { + assertPermission(); + if (args.length < 3) { + printHelp(CommandType.VRPLOT); + return; + } + switch (args[2].toUpperCase()) { + case "OWNER": { + assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); + if (args.length < 4) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyUsername); + return; + } + + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); + return; + } + + String targetArg = args[3]; + OfflinePlayer offlinePlayer; + UUID targetUUID; + + try { + if (UUIDUtils.isValidUUID(targetArg)) { + targetUUID = UUID.fromString(targetArg); + offlinePlayer = Bukkit.getOfflinePlayer(targetUUID); + } else { + offlinePlayer = Bukkit.getOfflinePlayer(targetArg); + targetUUID = offlinePlayer.getUniqueId(); + } + } catch (Exception ex) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().playerNotFoundWithUsername); + return; + } + + if (targetUUID == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().playerNotFoundWithUsername); + return; + } + + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); + return; + } + + // Optional: set expiry date/time if provided + if (args.length >= 5) { + String dateFormat = args[4]; + String timeFormat; + int year; + int month; + int dayOfMonth; + int hour = 0; + int minute = 0; + LocalDateTime localDateTime; + try { + String[] dateParts = dateFormat.split("/"); + year = Integer.parseInt(dateParts[2]); + month = Integer.parseInt(dateParts[1]); + dayOfMonth = Integer.parseInt(dateParts[0]); + if (args.length >= 6) { + timeFormat = args[5]; + String[] timeParts = timeFormat.split(":"); + hour = Integer.parseInt(timeParts[0]); + minute = Integer.parseInt(timeParts[1]); + } + localDateTime = LocalDateTime.of(year, month, dayOfMonth, hour, minute); + } catch (Exception e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().invalidDateProvided); + return; + } + plot.setOwnedUntilDate(localDateTime); + } + + // Special case: remote console + "assign" flag + if (sender instanceof RemoteConsoleCommandSender && args.length >= 7 + && args[6].equalsIgnoreCase("assign")) { + plot.setAssignedBy("SHOP_PURCHASE"); + } + + plot.setOwnedBy(targetUUID); + + // Safe display name for messages + String displayName = PlayerLookupUtil.getBestName(offlinePlayer); + if (displayName == null || displayName.isEmpty()) { + if (!targetArg.isEmpty()) { + displayName = targetArg; + } else { + displayName = targetUUID.toString().substring(0, 8); + } + } + + sender.sendMessage( + VirtualRealty.PREFIX + + VirtualRealty.getMessages().assignedTo.replaceAll("%assigned_to%", displayName) + ); + plot.update(); + return; + } + case "FLOOR": { + assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); + if (args.length < 4) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyMaterialName); + return; + } + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); + return; + } + Material material; + try { + material = Material.matchMaterial(args[3].split(":")[0].toUpperCase()); + if (material == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); + return; + } + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); + return; + } + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); + return; + } + + plot.setFloorMaterial(material); + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().newFloorMaterialSet); + plot.update(); + return; + } + case "BORDER": { + assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); + if (args.length < 4) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyMaterialName); + return; + } + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); + return; + } + Material material; + try { + material = Material.getMaterial(args[3].split(":")[0].toUpperCase()); + if (material == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); + return; + } + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().cantGetMaterial); + return; + } + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); + return; + } + + plot.setBorderMaterial(material); + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().newBorderMaterialSet); + plot.update(); + return; + } + case "EXPIRY": { + assertPermission(COMMAND_PERMISSION.getName() + args[0].toLowerCase() + "." + args[2].toLowerCase()); + if (args.length < 4) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().specifyExpiryDate); + return; + } + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (IllegalArgumentException e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().useNaturalNumbersOnly); + return; + } + String dateFormat = args[3]; + String timeFormat; + int year; + int month; + int dayOfMonth; + int hour = 0; + int minute = 0; + LocalDateTime localDateTime; + try { + String[] dateParts = dateFormat.split("/"); + year = Integer.parseInt(dateParts[2]); + month = Integer.parseInt(dateParts[1]); + dayOfMonth = Integer.parseInt(dateParts[0]); + if (args.length == 5) { + timeFormat = args[4]; + String[] timeParts = timeFormat.split(":"); + hour = Integer.parseInt(timeParts[0]); + minute = Integer.parseInt(timeParts[1]); + } + localDateTime = LocalDateTime.of(year, month, dayOfMonth, hour, minute); + } catch (Exception e) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().invalidDateProvided); + return; + } + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().noPlotFound); + return; + } + plot.setOwnedUntilDate(localDateTime); + sender.sendMessage(VirtualRealty.PREFIX + VirtualRealty.getMessages().ownedUntilUpdated); + plot.update(); + return; + } + default: { + for (String helpMessage : HELP) { + sender.sendMessage(helpMessage); + } + } + } + } } diff --git a/src/main/java/com/modnmetl/virtualrealty/listener/PlotEntranceListener.java b/src/main/java/com/modnmetl/virtualrealty/listener/PlotEntranceListener.java index a416704..6292a6c 100644 --- a/src/main/java/com/modnmetl/virtualrealty/listener/PlotEntranceListener.java +++ b/src/main/java/com/modnmetl/virtualrealty/listener/PlotEntranceListener.java @@ -1,15 +1,15 @@ package com.modnmetl.virtualrealty.listener; -import com.modnmetl.virtualrealty.model.plot.PlotSize; -import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.VirtualRealty; +import com.modnmetl.virtualrealty.manager.PlotManager; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.plot.PlotMember; +import com.modnmetl.virtualrealty.model.plot.PlotSize; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.OfflinePlayer; import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -18,102 +18,124 @@ import java.util.AbstractMap; import java.util.HashMap; import java.util.Map; -import java.util.Objects; +import java.util.UUID; public class PlotEntranceListener extends VirtualListener { - public HashMap> enteredPlot = new HashMap<>(); - - public PlotEntranceListener(VirtualRealty plugin) { - super(plugin); - } - - @SuppressWarnings("deprecation") - @EventHandler - public void onPlotMove(PlayerMoveEvent e) { - if (e.isCancelled()) - return; - Player player = e.getPlayer(); - Location to = e.getTo(); - if (to == null) - return; - Plot plot = PlotManager.getInstance().getPlot(to, true); - if (plot != null) { - OfflinePlayer offlinePlayer; - String enterPlotString = VirtualRealty.getMessages().enteredAvailablePlot; - if (plot.getOwnedBy() != null) { - offlinePlayer = Bukkit.getOfflinePlayer(plot.getOwnedBy()); - enterPlotString = VirtualRealty.getMessages().enteredOwnedPlot - .replaceAll("%owner%", Objects.requireNonNull(offlinePlayer.getName())) - .replaceAll("%plot_id%", plot.getID() + ""); - } - if (!enteredPlot.containsKey(player)) { - enteredPlot.put(player, new AbstractMap.SimpleEntry<>(plot, true)); - Plot newPlot = enteredPlot.get(player).getKey(); - if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { - if (newPlot.hasMembershipAccess(player.getUniqueId())) { - if (newPlot.getOwnedBy() != null && newPlot.getOwnedBy().equals(player.getUniqueId())) { - player.setGameMode(newPlot.getSelectedGameMode()); - } else if (newPlot.getMember(player.getUniqueId()) != null) { - PlotMember plotMember = newPlot.getMember(player.getUniqueId()); - player.setGameMode(plotMember.getSelectedGameMode()); - } - } - } - if (!VirtualRealty.getInstance().getServer().getBukkitVersion().startsWith("1.8")) { - if (VirtualRealty.getPluginConfiguration().plotSound) { - player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_TRAPDOOR_OPEN, 0.4f, 0.8f); - } - if (enteredPlot.get(player).getKey().getPlotSize() == PlotSize.AREA) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, - TextComponent.fromLegacyText(VirtualRealty.getMessages().enteredProtectedArea)); - } else { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, - TextComponent.fromLegacyText(enterPlotString)); - } - } - } else { - if (!enteredPlot.get(player).getValue()) { - enteredPlot.replace(player, new AbstractMap.SimpleEntry<>(plot, true)); - if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { - player.setGameMode(VirtualRealty.getPluginConfiguration().getDefaultPlotGamemode()); - } - } - } - } else { - if (!enteredPlot.containsKey(player)) - return; - if (enteredPlot.get(player).getValue()) { - OfflinePlayer offlinePlayer; - String leavePlotString = VirtualRealty.getMessages().leftAvailablePlot; - if (enteredPlot.get(player).getKey().getOwnedBy() != null) { - offlinePlayer = Bukkit.getOfflinePlayer(enteredPlot.get(player).getKey().getOwnedBy()); - leavePlotString = VirtualRealty.getMessages().leftOwnedPlot - .replaceAll("%owner%", Objects.requireNonNull(offlinePlayer.getName())) - .replaceAll("%plot_id%", enteredPlot.get(player).getKey().getID() + ""); - if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { - if (enteredPlot.get(player).getKey().hasMembershipAccess(player.getUniqueId())) { - player.setGameMode(Bukkit.getServer().getDefaultGameMode()); - } - } - } - if (!VirtualRealty.getInstance().getServer().getBukkitVersion().startsWith("1.8")) { - if (VirtualRealty.getPluginConfiguration().plotSound) { - player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_TRAPDOOR_CLOSE, 0.3f, 1f); - } - if (enteredPlot.get(player).getKey().getPlotSize() == PlotSize.AREA) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, - TextComponent.fromLegacyText(VirtualRealty.getMessages().leftProtectedArea)); - } else { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, - TextComponent.fromLegacyText(leavePlotString)); - } - } - enteredPlot.remove(player); - return; - } - enteredPlot.replace(player, new AbstractMap.SimpleEntry<>(enteredPlot.get(player).getKey(), false)); - } - } + public HashMap> enteredPlot = new HashMap<>(); + + public PlotEntranceListener(VirtualRealty plugin) { + super(plugin); + } + + @SuppressWarnings("deprecation") + @EventHandler + public void onPlotMove(PlayerMoveEvent e) { + if (e.isCancelled()) + return; + + Player player = e.getPlayer(); + Location to = e.getTo(); + if (to == null) + return; + + Plot plot = PlotManager.getInstance().getPlot(to, true); + if (plot != null) { + String enterPlotString = VirtualRealty.getMessages().enteredAvailablePlot; + + UUID ownerId = plot.getOwnedBy(); + if (ownerId != null) { + String ownerName = PlayerLookupUtil.getBestName(ownerId); + if (ownerName == null || ownerName.isEmpty()) { + ownerName = "Unknown"; + } + enterPlotString = VirtualRealty.getMessages().enteredOwnedPlot + .replaceAll("%owner%", ownerName) + .replaceAll("%plot_id%", String.valueOf(plot.getID())); + } + + if (!enteredPlot.containsKey(player)) { + enteredPlot.put(player, new AbstractMap.SimpleEntry<>(plot, true)); + Plot newPlot = enteredPlot.get(player).getKey(); + + // Gamemode handling + if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { + if (newPlot.hasMembershipAccess(player.getUniqueId())) { + if (ownerId != null && ownerId.equals(player.getUniqueId())) { + player.setGameMode(newPlot.getSelectedGameMode()); + } else if (newPlot.getMember(player.getUniqueId()) != null) { + PlotMember plotMember = newPlot.getMember(player.getUniqueId()); + player.setGameMode(plotMember.getSelectedGameMode()); + } + } + } + + // Sounds + action bar messages (1.9+ only) + if (!VirtualRealty.getInstance().getServer().getBukkitVersion().startsWith("1.8")) { + if (VirtualRealty.getPluginConfiguration().plotSound) { + player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_TRAPDOOR_OPEN, 0.4f, 0.8f); + } + if (enteredPlot.get(player).getKey().getPlotSize() == PlotSize.AREA) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, + TextComponent.fromLegacyText(VirtualRealty.getMessages().enteredProtectedArea)); + } else { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, + TextComponent.fromLegacyText(enterPlotString)); + } + } + } else { + if (!enteredPlot.get(player).getValue()) { + enteredPlot.replace(player, new AbstractMap.SimpleEntry<>(plot, true)); + if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { + player.setGameMode(VirtualRealty.getPluginConfiguration().getDefaultPlotGamemode()); + } + } + } + } else { + if (!enteredPlot.containsKey(player)) + return; + + if (enteredPlot.get(player).getValue()) { + String leavePlotString = VirtualRealty.getMessages().leftAvailablePlot; + + Plot lastPlot = enteredPlot.get(player).getKey(); + UUID ownerId = lastPlot.getOwnedBy(); + if (ownerId != null) { + String ownerName = PlayerLookupUtil.getBestName(ownerId); + if (ownerName == null || ownerName.isEmpty()) { + ownerName = "Unknown"; + } + + leavePlotString = VirtualRealty.getMessages().leftOwnedPlot + .replaceAll("%owner%", ownerName) + .replaceAll("%plot_id%", String.valueOf(lastPlot.getID())); + + if (VirtualRealty.getPluginConfiguration().enablePlotGamemode) { + if (lastPlot.hasMembershipAccess(player.getUniqueId())) { + player.setGameMode(Bukkit.getServer().getDefaultGameMode()); + } + } + } + + if (!VirtualRealty.getInstance().getServer().getBukkitVersion().startsWith("1.8")) { + if (VirtualRealty.getPluginConfiguration().plotSound) { + player.playSound(player.getLocation(), Sound.BLOCK_WOODEN_TRAPDOOR_CLOSE, 0.3f, 1f); + } + if (lastPlot.getPlotSize() == PlotSize.AREA) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, + TextComponent.fromLegacyText(VirtualRealty.getMessages().leftProtectedArea)); + } else { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, + TextComponent.fromLegacyText(leavePlotString)); + } + } + + enteredPlot.remove(player); + return; + } + + enteredPlot.replace(player, new AbstractMap.SimpleEntry<>(enteredPlot.get(player).getKey(), false)); + } + } } diff --git a/src/main/java/com/modnmetl/virtualrealty/listener/premium/PanelListener.java b/src/main/java/com/modnmetl/virtualrealty/listener/premium/PanelListener.java index 3aa8030..8ab94a1 100644 --- a/src/main/java/com/modnmetl/virtualrealty/listener/premium/PanelListener.java +++ b/src/main/java/com/modnmetl/virtualrealty/listener/premium/PanelListener.java @@ -1,15 +1,16 @@ package com.modnmetl.virtualrealty.listener.premium; import com.modnmetl.virtualrealty.VirtualRealty; -import com.modnmetl.virtualrealty.model.permission.ManagementPermission; +import com.modnmetl.virtualrealty.listener.VirtualListener; +import com.modnmetl.virtualrealty.model.other.ChatMessage; import com.modnmetl.virtualrealty.model.other.PanelType; +import com.modnmetl.virtualrealty.model.permission.ManagementPermission; import com.modnmetl.virtualrealty.model.permission.RegionPermission; -import com.modnmetl.virtualrealty.listener.VirtualListener; import com.modnmetl.virtualrealty.model.plot.Plot; import com.modnmetl.virtualrealty.model.plot.PlotMember; import com.modnmetl.virtualrealty.model.region.GridStructure; import com.modnmetl.virtualrealty.util.PanelUtil; -import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.util.PlayerLookupUtil; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -30,29 +31,36 @@ public PanelListener(VirtualRealty plugin) { public void onPanelClicked(InventoryClickEvent e) { UUID uuid = e.getWhoClicked().getUniqueId(); if (!PanelUtil.SELECTED_PANEL.containsKey(uuid)) return; + e.setCancelled(true); - Player player = ((Player) e.getWhoClicked()); + Player player = (Player) e.getWhoClicked(); + if (PanelUtil.SELECTED_PANEL.get(player.getUniqueId()) != PanelType.PLOTS) { - if (e.getInventory().getSize()-9 == e.getSlot()) { + if (e.getInventory().getSize() - 9 == e.getSlot()) { PanelUtil.openPreviousPage(player); return; } } + switch (PanelUtil.SELECTED_PANEL.get(uuid)) { + case PLOTS: { if (PanelUtil.SELECTED_PLOT_PAGE.containsKey(player.getUniqueId())) { int currentPageIndex = PanelUtil.SELECTED_PLOT_PAGE.get(player.getUniqueId()); + if (e.getSlot() == 8) { if (currentPageIndex - 1 > 0) { PanelUtil.openPlotsPage(player, currentPageIndex - 1); } } + if (e.getSlot() == 44) { VirtualRealty.debug(PanelUtil.hasNextPlotsPage(player, currentPageIndex) + " "); if (PanelUtil.hasNextPlotsPage(player, currentPageIndex)) { PanelUtil.openPlotsPage(player, currentPageIndex + 1); } } + if (e.getSlot() > 9 && e.getSlot() < 35) { Plot plot = PanelUtil.getPlot(e.getCurrentItem()); if (plot != null) { @@ -62,39 +70,47 @@ public void onPanelClicked(InventoryClickEvent e) { } break; } + case PLOT: { if (PanelUtil.SELECTED_PLOT.containsKey(player.getUniqueId())) { Plot plot = PanelUtil.SELECTED_PLOT.get(player.getUniqueId()); + if (e.getSlot() == 15) { - //TELEPORT + // TELEPORT player.closeInventory(); plot.teleportPlayer(player); ChatMessage.of(VirtualRealty.getMessages().teleportedToPlot).sendWithPrefix(player); return; } + if (plot.isOwnershipExpired()) { ChatMessage.of(VirtualRealty.getMessages().ownershipExpired).sendWithPrefix(player); return; } + if (e.getSlot() == 11) { - if (plot.getMembers().size() == 0) { + if (plot.getMembers().isEmpty()) { ChatMessage.of(VirtualRealty.getMessages().noPlotMembers).sendWithPrefix(player); return; } PanelUtil.openMembersPage(player, plot, 1); } + if (e.getSlot() == 12) { - //SETTINGS + // SETTINGS PanelUtil.openPlotSettings(player, plot); } + if (e.getSlot() == 14) { - //VISUAL BOUNDARY + // VISUAL BOUNDARY if (GridStructure.isCuboidGridDisplaying(player, plot.getID())) { ChatMessage.of(VirtualRealty.getMessages().visualBoundaryActive).sendWithPrefix(player); return; } + player.closeInventory(); ChatMessage.of(VirtualRealty.getMessages().visualBoundaryDisplayed).sendWithPrefix(player); + new BukkitRunnable() { @Override public void run() { @@ -115,21 +131,25 @@ public void run() { } break; } + case MEMBERS: { if (PanelUtil.SELECTED_PLOT.containsKey(player.getUniqueId())) { Plot plot = PanelUtil.SELECTED_PLOT.get(player.getUniqueId()); int currentPageIndex = PanelUtil.SELECTED_MEMBERS_PAGE.get(player.getUniqueId()); OfflinePlayer member = PanelUtil.getMember(e.getCurrentItem()); + if (member != null) { PanelUtil.openMember(player, plot, currentPageIndex, member); return; } + if (e.getSlot() == 8) { if (currentPageIndex - 1 > 0) { PanelUtil.openMembersPage(player, plot, currentPageIndex - 1); return; } } + if (e.getSlot() == 44) { if (PanelUtil.hasNextMembersPage(plot, currentPageIndex)) { PanelUtil.openMembersPage(player, plot, currentPageIndex + 1); @@ -139,41 +159,52 @@ public void run() { } break; } + case PLOT_SETTINGS: { if (PanelUtil.SELECTED_PLOT.containsKey(player.getUniqueId())) { Plot plot = PanelUtil.SELECTED_PLOT.get(player.getUniqueId()); RegionPermission plotPermission = RegionPermission.getPermission(e.getSlot() - 10); PlotMember plotMember = plot.getMember(player.getUniqueId()); + if (!Objects.nonNull(plotPermission)) return; + if (plotMember != null) { if (!plotMember.hasManagementPermission(ManagementPermission.PLOT_PERMISSIONS)) { ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(player); return; } } + plot.togglePermission(plotPermission); - String message = (plot.hasPermission(plotPermission) ? "§a" : "§c") + plotPermission.getName() + " has been " + (plot.hasPermission(plotPermission) ? "enabled" : "disabled") + " for non-member users."; + String message = (plot.hasPermission(plotPermission) ? "§a" : "§c") + + plotPermission.getName() + " has been " + + (plot.hasPermission(plotPermission) ? "enabled" : "disabled") + + " for non-member users."; ChatMessage.of(message).sendWithPrefix(player); PanelUtil.openPlotSettings(player, plot); plot.update(); } break; } + case MEMBER: { if (PanelUtil.SELECTED_PLOT.containsKey(player.getUniqueId())) { Plot plot = PanelUtil.SELECTED_PLOT.get(player.getUniqueId()); int membersPageIndex = PanelUtil.SELECTED_MEMBERS_PAGE.get(player.getUniqueId()); OfflinePlayer offlinePlayer = PanelUtil.SELECTED_MEMBER.get(player.getUniqueId()); + if (e.getSlot() == 12) { - //Management Permissions + // Management Permissions PanelUtil.openMemberManagementPermissions(player, plot, membersPageIndex, offlinePlayer); } + if (e.getSlot() == 14) { - //Plot Permissions + // Plot Permissions PanelUtil.openMemberPlotPermissions(player, plot, membersPageIndex, offlinePlayer); } + if (e.getSlot() == 26) { - //Kick Member + // Kick Member PlotMember plotMember = plot.getMember(player.getUniqueId()); if (plotMember != null) { if (!plotMember.hasManagementPermission(ManagementPermission.KICK_MEMBER)) { @@ -181,21 +212,38 @@ public void run() { return; } } + plot.removeMember(plot.getMember(offlinePlayer.getUniqueId())); - ChatMessage.of(VirtualRealty.getMessages().playerKick.replaceAll("%player%", offlinePlayer.getName())).sendWithPrefix(player); + + String displayName = PlayerLookupUtil.getBestName(offlinePlayer); + if (displayName == null || displayName.isEmpty()) { + UUID targetId = offlinePlayer.getUniqueId(); + displayName = (targetId != null) + ? targetId.toString().substring(0, 8) + : "Unknown"; + } + + ChatMessage.of( + VirtualRealty.getMessages().playerKick + .replaceAll("%player%", displayName) + ).sendWithPrefix(player); + if (PanelUtil.hasNextMembersPage(plot, membersPageIndex - 1)) { PanelUtil.openMembersPage(player, plot, membersPageIndex); return; } - if (plot.getMembers().size() == 0) { + + if (plot.getMembers().isEmpty()) { PanelUtil.openPlotPage(player, plot); return; } + PanelUtil.openMembersPage(player, plot, membersPageIndex - 1); } } break; } + case PLOT_PERMISSIONS: { if (PanelUtil.SELECTED_PLOT.containsKey(player.getUniqueId())) { Plot plot = PanelUtil.SELECTED_PLOT.get(player.getUniqueId()); @@ -204,15 +252,30 @@ public void run() { PlotMember plotMember = plot.getMember(offlinePlayer.getUniqueId()); RegionPermission plotPermission = RegionPermission.getPermission(e.getSlot() - 10); PlotMember panelMember = plot.getMember(player.getUniqueId()); + if (panelMember != null) { if (!panelMember.hasManagementPermission(ManagementPermission.PLOT_PERMISSIONS)) { ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(player); return; } } + if (!Objects.nonNull(plotPermission)) return; + plotMember.togglePermission(plotPermission); - String message = (plotMember.hasPermission(plotPermission) ? "§a" : "§c") + plotPermission.getName() + " has been " + (plotMember.hasPermission(plotPermission) ? "enabled" : "disabled") + " for " + offlinePlayer.getName(); + + String targetName = PlayerLookupUtil.getBestName(offlinePlayer); + if (targetName == null || targetName.isEmpty()) { + UUID targetId = offlinePlayer.getUniqueId(); + targetName = (targetId != null) + ? targetId.toString().substring(0, 8) + : "Unknown"; + } + + String message = (plotMember.hasPermission(plotPermission) ? "§a" : "§c") + + plotPermission.getName() + " has been " + + (plotMember.hasPermission(plotPermission) ? "enabled" : "disabled") + + " for " + targetName; ChatMessage.of(message).sendWithPrefix(player); PanelUtil.openMemberPlotPermissions(player, plot, membersPageIndex, offlinePlayer); plotMember.update(); @@ -227,13 +290,28 @@ public void run() { OfflinePlayer offlinePlayer = PanelUtil.SELECTED_MEMBER.get(player.getUniqueId()); PlotMember plotMember = plot.getMember(offlinePlayer.getUniqueId()); ManagementPermission managementPermission = ManagementPermission.getPermission(e.getSlot() - 12); + if (!plot.getPlotOwner().getUniqueId().equals(player.getUniqueId())) { ChatMessage.of(VirtualRealty.getMessages().noAccess).sendWithPrefix(player); return; } + if (!Objects.nonNull(managementPermission)) return; + plotMember.toggleManagementPermission(managementPermission); - String message = (plotMember.hasManagementPermission(managementPermission) ? "§a" : "§c") + managementPermission.getName() + " has been " + (plotMember.hasManagementPermission(managementPermission) ? "enabled" : "disabled") + " for " + offlinePlayer.getName(); + + String targetName = PlayerLookupUtil.getBestName(offlinePlayer); + if (targetName == null || targetName.isEmpty()) { + UUID targetId = offlinePlayer.getUniqueId(); + targetName = (targetId != null) + ? targetId.toString().substring(0, 8) + : "Unknown"; + } + + String message = (plotMember.hasManagementPermission(managementPermission) ? "§a" : "§c") + + managementPermission.getName() + " has been " + + (plotMember.hasManagementPermission(managementPermission) ? "enabled" : "disabled") + + " for " + targetName; ChatMessage.of(message).sendWithPrefix(player); PanelUtil.openMemberManagementPermissions(player, plot, membersPageIndex, offlinePlayer); plotMember.update(); @@ -252,5 +330,4 @@ public void onPanelLeave(InventoryCloseEvent e) { PanelUtil.SELECTED_MEMBER.remove(uuid); } - -} \ No newline at end of file +} diff --git a/src/main/java/com/modnmetl/virtualrealty/util/PanelUtil.java b/src/main/java/com/modnmetl/virtualrealty/util/PanelUtil.java index 0b83827..0842449 100644 --- a/src/main/java/com/modnmetl/virtualrealty/util/PanelUtil.java +++ b/src/main/java/com/modnmetl/virtualrealty/util/PanelUtil.java @@ -31,343 +31,469 @@ public final class PanelUtil { - public static final HashMap SELECTED_PLOT_PAGE = new HashMap<>(); - public static final HashMap SELECTED_MEMBERS_PAGE = new HashMap<>(); - public static final HashMap SELECTED_PANEL = new HashMap<>(); - public static final HashMap SELECTED_PLOT = new HashMap<>(); - public static final HashMap SELECTED_MEMBER = new HashMap<>(); - - public static final ItemStack blank = new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE, 1, (byte) 0).setName(" ") - .toItemStack(); - public static final ItemStack lightBlank = new ItemBuilder(Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1, (byte) 0) - .setName(" ").toItemStack(); - public static final ItemStack pageUp = new ItemBuilder( - SkullUtil.getSkull("3040fe836a6c2fbd2c7a9c8ec6be5174fddf1ac20f55e366156fa5f712e10")) - .setName("§7↑ Previous Page").toItemStack(); - public static final ItemStack pageDown = new ItemBuilder( - SkullUtil.getSkull("7437346d8bda78d525d19f540a95e4e79daeda795cbc5a13256236312cf")).setName("§7↓ Next Page") - .toItemStack(); - public static final ItemStack goBackward = new ItemBuilder(Material.REPEATER).setName("§c← Go Back").toItemStack(); - - public static void openPlotsPage(Player player, int page) { - if (page < 1) - return; - Plot[] plots = PlotManager.getInstance().getAccessPlots(player.getUniqueId()).values().stream() - .sorted(Comparator.comparingInt(Plot::getID)).skip(21L * (page - 1)).limit(21).toArray(Plot[]::new); - int[] plotSlots = new int[] { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, - 34 }; - Inventory inventory = Bukkit.createInventory(null, 45, - PanelType.PLOTS.getInventoryName() + (hasNextPlotsPage(player, 1) ? " | Page " + page : "")); - setBlank(inventory); - setLightBlank(inventory); - for (int slot = 0; slot < plots.length; slot++) { - Plot plot = plots[slot]; - inventory.setItem(plotSlots[slot], getPlotItem(plot, player)); - } - if (hasNextPlotsPage(player, page)) - inventory.setItem(44, pageDown); - if (page > 1) - inventory.setItem(8, pageUp); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOTS); - SELECTED_PLOT_PAGE.put(player.getUniqueId(), page); - } - - public static void openPlotPage(Player player, Plot plot) { - Inventory inventory = Bukkit.createInventory(player, 27, PanelType.PLOT.getInventoryName()); - ItemStack membersItem = new ItemBuilder( - SkullUtil.getSkull("b8e302cd0531be62a16757222b55202231ed40e2b5c2907ce7914a321b5287c2")) - .setName("§2Members").toItemStack(); - ItemStack settingsItem = new ItemBuilder(Material.REDSTONE).setName("§2Non-Member Permissions").toItemStack(); - ItemStack visualizationItem = new ItemBuilder( - SkullUtil.getSkull("775bca1af5cb1557c1794d23d907df1159320e14eba0581c25187dbeb22ba2cc")) - .setName("§2Visual Boundary").toItemStack(); - ItemStack teleportItem = new ItemBuilder(Material.ENDER_PEARL).setName("§2Teleport to the Plot").toItemStack(); - - setBlank(inventory); - inventory.setItem(0, getPlotItem(plot, player)); - inventory.setItem(11, membersItem); - inventory.setItem(12, settingsItem); - inventory.setItem(14, visualizationItem); - inventory.setItem(15, teleportItem); - inventory.setItem(PanelType.PLOT.getBackwardsButtonIndex(), goBackward); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openMembersPage(Player player, Plot plot, int pageIndex) { - if (pageIndex < 1) - return; - OfflinePlayer[] members = plot.getPlayerMembers().stream().sorted(Comparator.comparing(OfflinePlayer::getName)) - .skip(21L * (pageIndex - 1)).limit(21).toArray(OfflinePlayer[]::new); - int[] memberSlots = new int[] { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, - 34 }; - Inventory inventory = Bukkit.createInventory(null, 45, - PanelType.MEMBERS.getInventoryName() + (hasNextMembersPage(plot, 1) ? " | Page " + pageIndex : "")); - setBlank(inventory); - setLightBlank(inventory); - - inventory.setItem(0, getPlotItem(plot, player)); - for (int slot = 0; slot < members.length; slot++) { - OfflinePlayer member = members[slot]; - String lastPlayed = (member.isOnline() ? "§a" : "§c") + (member.getLastPlayed() == 0 ? "Playing" - : Plot.SHORT_PLOT_DATE_FORMAT.format(LocalDateTime - .ofInstant(Instant.ofEpochMilli(member.getLastPlayed()), ZoneId.systemDefault()))); - ItemBuilder memberItemBuilder = new ItemBuilder(Material.PLAYER_HEAD, 1, (byte) 3) - .setName((member.isOnline() ? "§a" : "§c") + member.getName()) - .addLoreLine(" §8┏ §fOnline: " + (member.isOnline() ? "§a✔" : "§c✘")) - .addLoreLine(" §8┗ §fLast played: §a" + lastPlayed).setSkullOwner(member.getName()); - ItemStack memberItem = memberItemBuilder.toItemStack(); - NBT.modify(memberItem, nbt -> { - nbt.setString("vrplot_member_uuid", member.getUniqueId().toString()); - }); - inventory.setItem(memberSlots[slot], memberItem); - } - if (hasNextMembersPage(plot, pageIndex)) - inventory.setItem(44, pageDown); - if (pageIndex > 1) - inventory.setItem(8, pageUp); - inventory.setItem(PanelType.MEMBERS.getBackwardsButtonIndex(), goBackward); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.MEMBERS); - SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openPlotSettings(Player player, Plot plot) { - int invSize = RegionPermission.values().length / 7 + (RegionPermission.values().length % 7 != 0 ? 1 : 0); - Inventory inventory = Bukkit.createInventory(player, (invSize * 9) + (2 * 9), - PanelType.PLOT_SETTINGS.getInventoryName()); - setBlank(inventory); - inventory.setItem(0, getPlotItem(plot, player)); - int currentSlot = 0; - int endings = 0; - for (RegionPermission permission : RegionPermission.values()) { - ItemBuilder itemBuilder = permission.getItem(); - itemBuilder.setName((plot.hasPermission(permission) ? "§a" : "§c") + permission.getName()); - if ((currentSlot - endings) % 7 == 0 && currentSlot != 0) { - currentSlot += 2; - endings += 2; - } - inventory.setItem(currentSlot + 10, itemBuilder.toItemStack()); - currentSlot++; - } - inventory.setItem(inventory.getSize() - 9, goBackward); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT_SETTINGS); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openMember(Player player, Plot plot, int pageIndex, OfflinePlayer member) { - if (pageIndex < 1) - return; - Inventory inventory = Bukkit.createInventory(player, 27, PanelType.MEMBER.getInventoryName()); - setBlank(inventory); - inventory.setItem(0, getPlotItem(plot, player)); - inventory.setItem(8, getMemberItem(member).toItemStack()); - inventory.setItem(12, new ItemBuilder(Material.BOOK).setName("§2Management Permissions").toItemStack()); - inventory.setItem(14, new ItemBuilder( - Material.MAP) - .setName("§2Plot Permissions").setLore(new ArrayList<>()).toItemStack()); - inventory.setItem(26, - new ItemBuilder( - Material.OAK_DOOR).setName("§cKick Member").setLore(new ArrayList<>()).toItemStack()); - inventory.setItem(PanelType.MEMBER.getBackwardsButtonIndex(), goBackward); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.MEMBER); - SELECTED_MEMBER.put(player.getUniqueId(), member); - SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openMemberPlotPermissions(Player player, Plot plot, int pageIndex, OfflinePlayer member) { - if (pageIndex < 1) - return; - PlotMember plotMember = plot.getMember(member.getUniqueId()); - int invSize = RegionPermission.values().length / 7 + (RegionPermission.values().length % 7 != 0 ? 1 : 0); - Inventory inventory = Bukkit.createInventory(player, (invSize * 9) + (2 * 9), - PanelType.PLOT_PERMISSIONS.getInventoryName()); - setBlank(inventory); - - inventory.setItem(0, getPlotItem(plot, player)); - inventory.setItem(8, getMemberItem(member).toItemStack()); - - int currentSlot = 0; - int endings = 0; - for (RegionPermission permission : RegionPermission.values()) { - ItemBuilder itemBuilder = permission.getItem(); - itemBuilder.setName((plotMember.hasPermission(permission) ? "§a" : "§c") + permission.getName()); - if ((currentSlot - endings) % 7 == 0 && currentSlot != 0) { - currentSlot += 2; - endings += 2; - } - inventory.setItem(currentSlot + 10, itemBuilder.toItemStack()); - currentSlot++; - } - inventory.setItem(inventory.getSize() - 9, goBackward); - - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT_PERMISSIONS); - SELECTED_MEMBER.put(player.getUniqueId(), member); - SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openMemberManagementPermissions(Player player, Plot plot, int pageIndex, OfflinePlayer member) { - if (pageIndex < 1) - return; - PlotMember plotMember = plot.getMember(member.getUniqueId()); - Inventory inventory = Bukkit.createInventory(player, 27, PanelType.MANAGEMENT_PERMISSIONS.getInventoryName()); - setBlank(inventory); - - inventory.setItem(0, getPlotItem(plot, player)); - inventory.setItem(8, getMemberItem(member).toItemStack()); - for (int i = 0; i < ManagementPermission.values().length; i++) { - ManagementPermission managementPermission = ManagementPermission.values()[i]; - ItemBuilder itemBuilder = managementPermission.getItem(); - itemBuilder.setName((plotMember.hasManagementPermission(managementPermission) ? "§a" : "§c") - + managementPermission.getName()); - inventory.setItem(i + 12, itemBuilder.toItemStack()); - } - - inventory.setItem(PanelType.MANAGEMENT_PERMISSIONS.getBackwardsButtonIndex(), goBackward); - player.openInventory(inventory); - SELECTED_PANEL.put(player.getUniqueId(), PanelType.MANAGEMENT_PERMISSIONS); - SELECTED_MEMBER.put(player.getUniqueId(), member); - SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); - SELECTED_PLOT.put(player.getUniqueId(), plot); - } - - public static void openPreviousPage(Player player) { - UUID uuid = player.getUniqueId(); - switch (SELECTED_PANEL.get(uuid)) { - case PLOT: { - openPlotsPage(player, 1); - break; - } - case MEMBERS: - case PLOT_SETTINGS: { - openPlotPage(player, SELECTED_PLOT.get(uuid)); - break; - } - case MEMBER: { - openMembersPage(player, SELECTED_PLOT.get(uuid), SELECTED_MEMBERS_PAGE.get(uuid)); - break; - } - case PLOT_PERMISSIONS: - case MANAGEMENT_PERMISSIONS: { - openMember(player, SELECTED_PLOT.get(uuid), SELECTED_MEMBERS_PAGE.get(uuid), SELECTED_MEMBER.get(uuid)); - break; - } - default: { - break; - } - } - } - - public static Plot getPlot(ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) - return null; - boolean hasTag = NBT.get(itemStack, nbt -> { - return nbt.hasTag("vrplot_plot_id"); - }); - if (hasTag) { - Integer plotId = NBT.get(itemStack, nbt -> { - return nbt.getInteger("vrplot_plot_id"); - }); - return PlotManager.getInstance().getPlot(plotId); - } - return null; - } - - public static ItemBuilder getMemberItem(OfflinePlayer member) { - String lastPlayed = (member.isOnline() ? "§a" : "§c") + (member.getLastPlayed() == 0 ? "Playing" - : Plot.SHORT_PLOT_DATE_FORMAT.format( - LocalDateTime.ofInstant(Instant.ofEpochMilli(member.getLastPlayed()), ZoneId.systemDefault()))); - return new ItemBuilder( Material.PLAYER_HEAD, - 1, (byte) 3).setName((member.isOnline() ? "§a" : "§c") + member.getName()) - .addLoreLine(" §8┏ §fOnline: " + (member.isOnline() ? "§a✔" : "§c✘")) - .addLoreLine(" §8┗ §fLast played: §a" + lastPlayed).setSkullOwner(member.getName()); - } - - public static ItemStack getPlotItem(Plot plot, Player player) { - LocalDateTime ownedUntilDate = plot.getOwnedUntilDate(); - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); - char color; - String skullURL; - - int daysUntilExpirationThreshold = VirtualRealty.getPluginConfiguration().daysUntilExpirationThreshold; - if (plot.isOwnershipExpired()) { - color = 'c'; - skullURL = "fbeb2546564af4df7f7f589423f68102dea69cd4466b0583c474e5ac693b2b99"; - } else { - LocalDateTime now = LocalDateTime.now(); - long daysUntilExpiration = ChronoUnit.DAYS.between(now, ownedUntilDate); - - if (daysUntilExpiration <= daysUntilExpirationThreshold) { - color = 'e'; - skullURL = "66245fb397b7c2b3a36e2a24d496be258f1cdf41054f99e9c65e1a673add7b4"; - } else { - color = 'a'; - skullURL = "16bb9fb97ba87cb727cd0ff477f769370bea19ccbfafb581629cd5639f2fec2b"; - } - } - ItemStack plotItemStack = new ItemBuilder(SkullUtil.getSkull(skullURL)).setName("§" + color + "Plot") - .addLoreLine(" §8┏ §fID: §8#§7" + plot.getID()) - .addLoreLine(" §8┣ §fMembership: §" + color - + (plot.getPlotOwner().getUniqueId().equals(player.getUniqueId()) ? "OWNER" : "MEMBER")) - .addLoreLine(" §8┣ §fSize: §" + color + plot.getPlotSize().name()) - .addLoreLine(" §8┣ §fCreated: §" + color + plot.getCreatedAt().format(Plot.SHORT_PLOT_DATE_FORMAT)) - .addLoreLine(" §8┗ §fOwned Until: §" + color + dateTimeFormatter.format(ownedUntilDate)).toItemStack(); - - NBT.modify(plotItemStack, nbt -> { - nbt.setInteger("vrplot_plot_id", plot.getID()); - }); - return plotItemStack; - } - - public static OfflinePlayer getMember(ItemStack itemStack) { - if (itemStack == null || itemStack.getType() == Material.AIR) - return null; - boolean hasMemberUuid = NBT.get(itemStack, nbt -> { - return nbt.hasTag("vrplot_member_uuid"); - }); - if (hasMemberUuid) { - String memberUuid = NBT.get(itemStack, nbt -> { - return nbt.getString("vrplot_member_uuid"); - }); - return Bukkit.getOfflinePlayer(UUID.fromString(memberUuid)); - } - return null; - } - - private static void setLightBlank(Inventory inventory, int range) { - int[] dataSlot = new int[] { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, - 34 }; - for (int i = 0; i < range; i++) { - inventory.setItem(dataSlot[i], lightBlank); - } - } - - private static void setLightBlank(Inventory inventory) { - setLightBlank(inventory, 21); - } - - private static void setBlank(Inventory inventory) { - for (int slot = 0; slot < inventory.getSize(); slot++) { - inventory.setItem(slot, blank); - } - } - - public static boolean hasNextPlotsPage(Player player, int page) { - HashMap plots = PlotManager.getInstance().getAccessPlots(player.getUniqueId()); - int length = plots.values().stream().skip(21L * page).toArray().length; - return length > 0; - } - - public static boolean hasNextMembersPage(Plot plot, int page) { - return plot.getMembers().stream().skip(21L * page).toArray().length > 0; - } - -} \ No newline at end of file + public static final HashMap SELECTED_PLOT_PAGE = new HashMap<>(); + public static final HashMap SELECTED_MEMBERS_PAGE = new HashMap<>(); + public static final HashMap SELECTED_PANEL = new HashMap<>(); + public static final HashMap SELECTED_PLOT = new HashMap<>(); + public static final HashMap SELECTED_MEMBER = new HashMap<>(); + + public static final ItemStack blank = new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE, 1, (byte) 0) + .setName(" ") + .toItemStack(); + public static final ItemStack lightBlank = new ItemBuilder(Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1, (byte) 0) + .setName(" ") + .toItemStack(); + public static final ItemStack pageUp = new ItemBuilder( + SkullUtil.getSkull("3040fe836a6c2fbd2c7a9c8ec6be5174fddf1ac20f55e366156fa5f712e10")) + .setName("§7↑ Previous Page") + .toItemStack(); + public static final ItemStack pageDown = new ItemBuilder( + SkullUtil.getSkull("7437346d8bda78d525d19f540a95e4e79daeda795cbc5a13256236312cf")) + .setName("§7↓ Next Page") + .toItemStack(); + public static final ItemStack goBackward = new ItemBuilder(Material.REPEATER) + .setName("§c← Go Back") + .toItemStack(); + + private PanelUtil() { + } + + public static void openPlotsPage(Player player, int page) { + if (page < 1) + return; + + Plot[] plots = PlotManager.getInstance().getAccessPlots(player.getUniqueId()).values().stream() + .sorted(Comparator.comparingInt(Plot::getID)) + .skip(21L * (page - 1)) + .limit(21) + .toArray(Plot[]::new); + + int[] plotSlots = new int[]{ + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34 + }; + + Inventory inventory = Bukkit.createInventory( + null, + 45, + PanelType.PLOTS.getInventoryName() + (hasNextPlotsPage(player, 1) ? " | Page " + page : "") + ); + + setBlank(inventory); + setLightBlank(inventory); + + for (int slot = 0; slot < plots.length; slot++) { + Plot plot = plots[slot]; + inventory.setItem(plotSlots[slot], getPlotItem(plot, player)); + } + + if (hasNextPlotsPage(player, page)) { + inventory.setItem(44, pageDown); + } + if (page > 1) { + inventory.setItem(8, pageUp); + } + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOTS); + SELECTED_PLOT_PAGE.put(player.getUniqueId(), page); + } + + public static void openPlotPage(Player player, Plot plot) { + Inventory inventory = Bukkit.createInventory(player, 27, PanelType.PLOT.getInventoryName()); + + ItemStack membersItem = new ItemBuilder( + SkullUtil.getSkull("b8e302cd0531be62a16757222b55202231ed40e2b5c2907ce7914a321b5287c2")) + .setName("§2Members") + .toItemStack(); + + ItemStack settingsItem = new ItemBuilder(Material.REDSTONE) + .setName("§2Non-Member Permissions") + .toItemStack(); + + ItemStack visualizationItem = new ItemBuilder( + SkullUtil.getSkull("775bca1af5cb1557c1794d23d907df1159320e14eba0581c25187dbeb22ba2cc")) + .setName("§2Visual Boundary") + .toItemStack(); + + ItemStack teleportItem = new ItemBuilder(Material.ENDER_PEARL) + .setName("§2Teleport to the Plot") + .toItemStack(); + + setBlank(inventory); + + inventory.setItem(0, getPlotItem(plot, player)); + inventory.setItem(11, membersItem); + inventory.setItem(12, settingsItem); + inventory.setItem(14, visualizationItem); + inventory.setItem(15, teleportItem); + inventory.setItem(PanelType.PLOT.getBackwardsButtonIndex(), goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openMembersPage(Player player, Plot plot, int pageIndex) { + if (pageIndex < 1) + return; + + // Sort by safe display name (works for Bedrock / Floodgate too) + OfflinePlayer[] members = plot.getPlayerMembers().stream() + .sorted(Comparator.comparing(p -> { + String name = PlayerLookupUtil.getBestName(p); + return name == null ? "" : name.toLowerCase(); + })) + .skip(21L * (pageIndex - 1)) + .limit(21) + .toArray(OfflinePlayer[]::new); + + int[] memberSlots = new int[]{ + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34 + }; + + Inventory inventory = Bukkit.createInventory( + null, + 45, + PanelType.MEMBERS.getInventoryName() + (hasNextMembersPage(plot, 1) ? " | Page " + pageIndex : "") + ); + + setBlank(inventory); + setLightBlank(inventory); + + inventory.setItem(0, getPlotItem(plot, player)); + + for (int slot = 0; slot < members.length; slot++) { + OfflinePlayer member = members[slot]; + ItemBuilder memberItemBuilder = getMemberItem(member); + ItemStack memberItem = memberItemBuilder.toItemStack(); + + // Store UUID on the item for later lookup (use original NBT-API style) + NBT.modify(memberItem, nbt -> { + nbt.setString("vrplot_member_uuid", member.getUniqueId().toString()); + }); + + inventory.setItem(memberSlots[slot], memberItem); + } + + if (hasNextMembersPage(plot, pageIndex)) { + inventory.setItem(44, pageDown); + } + if (pageIndex > 1) { + inventory.setItem(8, pageUp); + } + + inventory.setItem(PanelType.MEMBERS.getBackwardsButtonIndex(), goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.MEMBERS); + SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openPlotSettings(Player player, Plot plot) { + int invSize = RegionPermission.values().length / 7 + + (RegionPermission.values().length % 7 != 0 ? 1 : 0); + Inventory inventory = Bukkit.createInventory(player, (invSize * 9) + (2 * 9), + PanelType.PLOT_SETTINGS.getInventoryName()); + + setBlank(inventory); + inventory.setItem(0, getPlotItem(plot, player)); + + int currentSlot = 0; + int endings = 0; + + for (RegionPermission permission : RegionPermission.values()) { + ItemBuilder itemBuilder = permission.getItem(); + itemBuilder.setName((plot.hasPermission(permission) ? "§a" : "§c") + permission.getName()); + + if ((currentSlot - endings) % 7 == 0 && currentSlot != 0) { + currentSlot += 2; + endings += 2; + } + + inventory.setItem(currentSlot + 10, itemBuilder.toItemStack()); + currentSlot++; + } + + inventory.setItem(inventory.getSize() - 9, goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT_SETTINGS); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openMember(Player player, Plot plot, int pageIndex, OfflinePlayer member) { + if (pageIndex < 1) + return; + + Inventory inventory = Bukkit.createInventory(player, 27, PanelType.MEMBER.getInventoryName()); + + setBlank(inventory); + inventory.setItem(0, getPlotItem(plot, player)); + inventory.setItem(8, getMemberItem(member).toItemStack()); + + inventory.setItem(12, new ItemBuilder(Material.BOOK) + .setName("§2Management Permissions") + .toItemStack()); + + inventory.setItem(14, new ItemBuilder(Material.MAP) + .setName("§2Plot Permissions") + .setLore(new ArrayList<>()) + .toItemStack()); + + inventory.setItem(26, new ItemBuilder(Material.OAK_DOOR) + .setName("§cKick Member") + .setLore(new ArrayList<>()) + .toItemStack()); + + inventory.setItem(PanelType.MEMBER.getBackwardsButtonIndex(), goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.MEMBER); + SELECTED_MEMBER.put(player.getUniqueId(), member); + SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openMemberPlotPermissions(Player player, Plot plot, int pageIndex, OfflinePlayer member) { + if (pageIndex < 1) + return; + + PlotMember plotMember = plot.getMember(member.getUniqueId()); + + int invSize = RegionPermission.values().length / 7 + + (RegionPermission.values().length % 7 != 0 ? 1 : 0); + + Inventory inventory = Bukkit.createInventory(player, (invSize * 9) + (2 * 9), + PanelType.PLOT_PERMISSIONS.getInventoryName()); + + setBlank(inventory); + + inventory.setItem(0, getPlotItem(plot, player)); + inventory.setItem(8, getMemberItem(member).toItemStack()); + + int currentSlot = 0; + int endings = 0; + + for (RegionPermission permission : RegionPermission.values()) { + ItemBuilder itemBuilder = permission.getItem(); + itemBuilder.setName((plotMember.hasPermission(permission) ? "§a" : "§c") + permission.getName()); + + if ((currentSlot - endings) % 7 == 0 && currentSlot != 0) { + currentSlot += 2; + endings += 2; + } + + inventory.setItem(currentSlot + 10, itemBuilder.toItemStack()); + currentSlot++; + } + + inventory.setItem(inventory.getSize() - 9, goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.PLOT_PERMISSIONS); + SELECTED_MEMBER.put(player.getUniqueId(), member); + SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openMemberManagementPermissions(Player player, Plot plot, int pageIndex, OfflinePlayer member) { + if (pageIndex < 1) + return; + + PlotMember plotMember = plot.getMember(member.getUniqueId()); + Inventory inventory = Bukkit.createInventory(player, 27, + PanelType.MANAGEMENT_PERMISSIONS.getInventoryName()); + + setBlank(inventory); + + inventory.setItem(0, getPlotItem(plot, player)); + inventory.setItem(8, getMemberItem(member).toItemStack()); + + for (int i = 0; i < ManagementPermission.values().length; i++) { + ManagementPermission managementPermission = ManagementPermission.values()[i]; + ItemBuilder itemBuilder = managementPermission.getItem(); + itemBuilder.setName((plotMember.hasManagementPermission(managementPermission) ? "§a" : "§c") + + managementPermission.getName()); + inventory.setItem(i + 12, itemBuilder.toItemStack()); + } + + inventory.setItem(PanelType.MANAGEMENT_PERMISSIONS.getBackwardsButtonIndex(), goBackward); + + player.openInventory(inventory); + SELECTED_PANEL.put(player.getUniqueId(), PanelType.MANAGEMENT_PERMISSIONS); + SELECTED_MEMBER.put(player.getUniqueId(), member); + SELECTED_MEMBERS_PAGE.put(player.getUniqueId(), pageIndex); + SELECTED_PLOT.put(player.getUniqueId(), plot); + } + + public static void openPreviousPage(Player player) { + UUID uuid = player.getUniqueId(); + switch (SELECTED_PANEL.get(uuid)) { + case PLOT: { + openPlotsPage(player, 1); + break; + } + case MEMBERS: + case PLOT_SETTINGS: { + openPlotPage(player, SELECTED_PLOT.get(uuid)); + break; + } + case MEMBER: { + openMembersPage(player, SELECTED_PLOT.get(uuid), SELECTED_MEMBERS_PAGE.get(uuid)); + break; + } + case PLOT_PERMISSIONS: + case MANAGEMENT_PERMISSIONS: { + openMember(player, SELECTED_PLOT.get(uuid), + SELECTED_MEMBERS_PAGE.get(uuid), SELECTED_MEMBER.get(uuid)); + break; + } + default: { + break; + } + } + } + + public static Plot getPlot(ItemStack itemStack) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return null; + + boolean hasTag = NBT.get(itemStack, nbt -> { + return nbt.hasTag("vrplot_plot_id"); + }); + + if (hasTag) { + Integer plotId = NBT.get(itemStack, nbt -> { + return nbt.getInteger("vrplot_plot_id"); + }); + return PlotManager.getInstance().getPlot(plotId); + } + return null; + } + + public static ItemBuilder getMemberItem(OfflinePlayer member) { + String lastPlayed = (member.isOnline() ? "§a" : "§c") + + (member.getLastPlayed() == 0 + ? "Playing" + : Plot.SHORT_PLOT_DATE_FORMAT.format( + LocalDateTime.ofInstant( + Instant.ofEpochMilli(member.getLastPlayed()), + ZoneId.systemDefault() + ) + )); + + String displayName = PlayerLookupUtil.getBestName(member); + if (displayName == null || displayName.isEmpty()) { + UUID id = member.getUniqueId(); + displayName = id == null ? "Unknown" : id.toString().substring(0, 8); + } + + // Skull owner name – try real Bukkit name first, then fallback to displayName + String skullOwnerName = member.getName(); + if (skullOwnerName == null || skullOwnerName.isEmpty()) { + skullOwnerName = displayName; + } + + return new ItemBuilder(Material.PLAYER_HEAD, 1, (byte) 3) + .setName((member.isOnline() ? "§a" : "§c") + displayName) + .addLoreLine(" §8┏ §fOnline: " + (member.isOnline() ? "§a✔" : "§c✘")) + .addLoreLine(" §8┗ §fLast played: §a" + lastPlayed) + .setSkullOwner(skullOwnerName); + } + + public static ItemStack getPlotItem(Plot plot, Player player) { + LocalDateTime ownedUntilDate = plot.getOwnedUntilDate(); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + char color; + String skullURL; + + int daysUntilExpirationThreshold = VirtualRealty.getPluginConfiguration().daysUntilExpirationThreshold; + + if (plot.isOwnershipExpired()) { + color = 'c'; + skullURL = "fbeb2546564af4df7f7f589423f68102dea69cd4466b0583c474e5ac693b2b99"; + } else { + LocalDateTime now = LocalDateTime.now(); + long daysUntilExpiration = ChronoUnit.DAYS.between(now, ownedUntilDate); + + if (daysUntilExpiration <= daysUntilExpirationThreshold) { + color = 'e'; + skullURL = "66245fb397b7c2b3a36e2a24d496be258f1cdf41054f99e9c65e1a673add7b4"; + } else { + color = 'a'; + skullURL = "16bb9fb97ba87cb727cd0ff477f769370bea19ccbfafb581629cd5639f2fec2b"; + } + } + + ItemStack plotItemStack = new ItemBuilder(SkullUtil.getSkull(skullURL)) + .setName("§" + color + "Plot") + .addLoreLine(" §8┏ §fID: §8#§7" + plot.getID()) + .addLoreLine(" §8┣ §fMembership: §" + color + + (plot.getPlotOwner().getUniqueId().equals(player.getUniqueId()) ? "OWNER" : "MEMBER")) + .addLoreLine(" §8┣ §fSize: §" + color + plot.getPlotSize().name()) + .addLoreLine(" §8┣ §fCreated: §" + color + plot.getCreatedAt().format(Plot.SHORT_PLOT_DATE_FORMAT)) + .addLoreLine(" §8┗ §fOwned Until: §" + color + dateTimeFormatter.format(ownedUntilDate)) + .toItemStack(); + + // Original NBT-API style + NBT.modify(plotItemStack, nbt -> { + nbt.setInteger("vrplot_plot_id", plot.getID()); + }); + + return plotItemStack; + } + + public static OfflinePlayer getMember(ItemStack itemStack) { + if (itemStack == null || itemStack.getType() == Material.AIR) + return null; + + boolean hasMemberUuid = NBT.get(itemStack, nbt -> { + return nbt.hasTag("vrplot_member_uuid"); + }); + + if (hasMemberUuid) { + String memberUuid = NBT.get(itemStack, nbt -> { + return nbt.getString("vrplot_member_uuid"); + }); + return Bukkit.getOfflinePlayer(UUID.fromString(memberUuid)); + } + return null; + } + + private static void setLightBlank(Inventory inventory, int range) { + int[] dataSlot = new int[]{ + 10, 11, 12, 13, 14, 15, 16, + 19, 20, 21, 22, 23, 24, 25, + 28, 29, 30, 31, 32, 33, 34 + }; + for (int i = 0; i < range && i < dataSlot.length; i++) { + inventory.setItem(dataSlot[i], lightBlank); + } + } + + private static void setLightBlank(Inventory inventory) { + setLightBlank(inventory, 21); + } + + private static void setBlank(Inventory inventory) { + for (int slot = 0; slot < inventory.getSize(); slot++) { + inventory.setItem(slot, blank); + } + } + + public static boolean hasNextPlotsPage(Player player, int page) { + HashMap plots = PlotManager.getInstance().getAccessPlots(player.getUniqueId()); + int length = plots.values().stream().skip(21L * page).toArray().length; + return length > 0; + } + + public static boolean hasNextMembersPage(Plot plot, int page) { + return plot.getMembers().stream().skip(21L * page).toArray().length > 0; + } + +} diff --git a/src/main/java/com/modnmetl/virtualrealty/util/PlayerLookupUtil.java b/src/main/java/com/modnmetl/virtualrealty/util/PlayerLookupUtil.java new file mode 100644 index 0000000..8103e80 --- /dev/null +++ b/src/main/java/com/modnmetl/virtualrealty/util/PlayerLookupUtil.java @@ -0,0 +1,142 @@ +package com.modnmetl.virtualrealty.util; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Centralised, null-safe player name lookup. + * + * Handles: + * - Online Java players + * - Offline players with cached names + * - Floodgate / Bedrock UUIDs that may not have names yet + * - Missing profiles (falls back to short UUID string) + * + * All methods are safe to call on Paper 1.21.x and in Geyser/Floodgate setups. + */ +public final class PlayerLookupUtil { + + // Simple in-memory cache to avoid hammering Bukkit lookups repeatedly. + private static final Map NAME_CACHE = new ConcurrentHashMap<>(); + + private PlayerLookupUtil() { + // utility + } + + /** + * Manually remember a mapping (useful from join listeners, etc.). + */ + public static void remember(UUID uuid, String name) { + if (uuid == null || name == null || name.isEmpty()) { + return; + } + NAME_CACHE.put(uuid, name); + } + + /** + * Get the best display name we can for this UUID. + * + * Never throws; returns: + * - Player#getName() if online + * - OfflinePlayer#getName() if available + * - cached name from this util if known + * - short UUID string as a last resort + * + * May return null only if uuid is null. + */ + public static String getBestName(UUID uuid) { + if (uuid == null) { + return null; + } + + // 0. Our own cache first (fast path, avoids frequent Bukkit calls) + String cached = NAME_CACHE.get(uuid); + if (cached != null && !cached.isEmpty()) { + return cached; + } + + // 1. If they're online, trust the live Player object + Player online = Bukkit.getPlayer(uuid); + if (online != null) { + String name = online.getName(); + if (name != null && !name.isEmpty()) { + NAME_CACHE.put(uuid, name); + return name; + } + } + + // 2. Try the OfflinePlayer cache + OfflinePlayer offline = Bukkit.getOfflinePlayer(uuid); + if (offline != null) { + String name = offline.getName(); + if (name != null && !name.isEmpty()) { + NAME_CACHE.put(uuid, name); + return name; + } + } + + // 3. Still nothing? Use a short UUID string as a stable fallback. + // This is safe because UUID.toString() is always 36 chars. + String shortId = uuid.toString().substring(0, 8); + NAME_CACHE.put(uuid, shortId); + return shortId; + } + + /** + * Null-safe helper when you already have an OfflinePlayer. + * Delegates to getBestName(UUID) when needed. + */ + public static String getBestName(OfflinePlayer offlinePlayer) { + if (offlinePlayer == null) { + return null; + } + + UUID uuid = offlinePlayer.getUniqueId(); + + // If it's actually a Player, use that directly + if (offlinePlayer instanceof Player) { + String name = ((Player) offlinePlayer).getName(); + if (name != null && !name.isEmpty()) { + if (uuid != null) { + NAME_CACHE.put(uuid, name); + } + return name; + } + } + + // Try OfflinePlayer#getName first + String name = offlinePlayer.getName(); + if (name != null && !name.isEmpty()) { + if (uuid != null) { + NAME_CACHE.put(uuid, name); + } + return name; + } + + // Fallback to UUID-based lookup (will handle cache, online check, etc.) + if (uuid == null) { + return null; + } + return getBestName(uuid); + } + + /** + * Convenience: try best name, else fall back to a provided string, + * else short UUID. Handy when you have the original argument (like a username). + */ + public static String getBestNameOrFallback(UUID uuid, String fallback) { + String best = getBestName(uuid); + if (best != null && !best.isEmpty()) { + return best; + } + if (fallback != null && !fallback.isEmpty()) { + return fallback; + } + return uuid == null ? null : uuid.toString().substring(0, 8); + } +}