diff --git a/src/com/djrapitops/plan/PlanCommand.java b/src/com/djrapitops/plan/PlanCommand.java index 21b5222f9..fdecacac0 100644 --- a/src/com/djrapitops/plan/PlanCommand.java +++ b/src/com/djrapitops/plan/PlanCommand.java @@ -6,6 +6,7 @@ import com.djrapitops.plan.command.commands.AnalyzeCommand; import com.djrapitops.plan.command.commands.HelpCommand; import com.djrapitops.plan.command.commands.InspectCommand; import com.djrapitops.plan.command.commands.ReloadCommand; +import com.djrapitops.plan.command.commands.SearchCommand; import com.djrapitops.plan.javaTools.Editor; import org.bukkit.ChatColor; @@ -27,6 +28,7 @@ public class PlanCommand implements CommandExecutor { commands.add(new HelpCommand(plugin, this)); commands.add(new InspectCommand(plugin)); commands.add(new AnalyzeCommand(plugin)); + commands.add(new SearchCommand(plugin)); commands.add(new ReloadCommand(plugin)); } @@ -70,14 +72,14 @@ public class PlanCommand implements CommandExecutor { return true; } + boolean console = !(sender instanceof Player); + if (!sender.hasPermission(command.getPermission())) { // Phrase.NO_PERMISSION_FOR_COMMAND.sendWithPrefix( sender ); sender.sendMessage(ChatColor.RED + "[PLAN] You do not have the required permmission."); return true; } - boolean console = !(sender instanceof Player); - if (console && args.length < 2 && command.getCommandType() == CommandType.CONSOLE_WITH_ARGUMENTS) { // Phrase.COMMAND_NEEDS_ARGUMENTS.sendWithPrefix( sender ); sender.sendMessage(ChatColor.RED + "[PLAN] Command requires arguments."); diff --git a/src/com/djrapitops/plan/command/commands/AnalyzeCommand.java b/src/com/djrapitops/plan/command/commands/AnalyzeCommand.java index 4e0a3fb2a..3078b9fef 100644 --- a/src/com/djrapitops/plan/command/commands/AnalyzeCommand.java +++ b/src/com/djrapitops/plan/command/commands/AnalyzeCommand.java @@ -12,6 +12,7 @@ import java.util.UUID; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public class AnalyzeCommand extends SubCommand { @@ -31,17 +32,18 @@ public class AnalyzeCommand extends SubCommand { ChatColor textColor = ChatColor.GRAY; for (String arg : args) { if (arg.toLowerCase().equals("-refresh")) { - if (sender.hasPermission("plan.analyze.refresh")) { + if (sender.hasPermission("plan.analyze.refresh") || !(sender instanceof Player)) { refreshAnalysisData(sender); } } } - if (this.playerData == null || this.refreshDate == null || this.analyzedPlayerdata == null) { + if (this.playerData == null || this.refreshDate == null || this.analyzedPlayerdata == null || DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()).contains("m")) { refreshAnalysisData(sender); } //header - sender.sendMessage(textColor + "-- [" + operatorColor + "PLAN - Analysis results, refreshed " + DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()) + " ago:" + textColor + "] --"); + sender.sendMessage(textColor + "-- [" + operatorColor + "PLAN - Analysis results, refreshed " + + DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()) + " ago:" + textColor + "] --"); List dataList = DataFormatUtils.turnDataHashMapToSortedListOfArrays(analyzedPlayerdata); @@ -58,9 +60,11 @@ public class AnalyzeCommand extends SubCommand { ChatColor textColor = ChatColor.GRAY; sender.sendMessage(textColor + "[" + operatorColor + "Plan" + textColor + "] " + "Refreshing playerData, this might take a while.."); - this.playerData = DataUtils.getTotalData(); + this.playerData = DataUtils.getTotalData(DataUtils.getMatchingDisplaynames(true)); this.refreshDate = new Date(); this.analyzedPlayerdata = DataUtils.analyze(this.playerData); + sender.sendMessage(textColor + "[" + operatorColor + "Plan" + textColor + "] " + + "Refreshed, took "+DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date())); } @Deprecated diff --git a/src/com/djrapitops/plan/command/commands/InspectCommand.java b/src/com/djrapitops/plan/command/commands/InspectCommand.java index 99182b320..c72121cbd 100644 --- a/src/com/djrapitops/plan/command/commands/InspectCommand.java +++ b/src/com/djrapitops/plan/command/commands/InspectCommand.java @@ -31,7 +31,7 @@ public class InspectCommand extends SubCommand { @Override public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { - String playerName = getPlayerDisplayname(args, sender); + String playerName = DataUtils.getPlayerDisplayname(args, sender); if (this.plugin.getHooks().isEmpty()) { this.plugin.logError("noHookedPluginsError on InspectCommand"); @@ -50,7 +50,7 @@ public class InspectCommand extends SubCommand { format = false; } } - + Date refreshDate = new Date(); HashMap data = DataUtils.getData(allData, playerName); if (format && !data.isEmpty()) { data = DataFormatUtils.removeExtraDataPoints(data); @@ -68,7 +68,7 @@ public class InspectCommand extends SubCommand { ChatColor textColor = ChatColor.GRAY; //header - sender.sendMessage(textColor + "-- [" + operatorColor + "PLAN - Inspect results: " + playerName + textColor + "] --"); + sender.sendMessage(textColor + "-- [" + operatorColor + "PLAN - Inspect results: " + playerName +" - took "+DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date())+ textColor + "] --"); for (String[] dataString : dataList) { sender.sendMessage("" + operatorColor + dataString[0].charAt(4) + dataString[0].toLowerCase().substring(5) + ": " + textColor + dataString[1]); @@ -77,36 +77,21 @@ public class InspectCommand extends SubCommand { return true; } + // Use DataUtils.getData instead @Deprecated public HashMap getData(boolean allData, String playerName) { return DataUtils.getData(allData, playerName); } + // Use DataFormatUtils.removeExtraDataPoints instead @Deprecated public HashMap format(HashMap data) throws NumberFormatException { return DataFormatUtils.removeExtraDataPoints(data); } + // Use DataUtils.getPlayerDisplayname instead + @Deprecated private String getPlayerDisplayname(String[] args, CommandSender sender) { - String playerName = ""; - if (args.length > 0) { - if ((args[0].equals("-a")) || (args[0].equals("-r"))) { - playerName = "ArgumentGivenError"; - plugin.log("No username given, returned empty username."); - - plugin.logToFile("INSPECT-GETNAME\nNo username given, returned empty username.\n" + args[0]); - - } else if (sender.hasPermission("plan.inspect.other")) { - playerName = args[0]; - } - } else { - try { - Player player = plugin.getServer().getPlayer(UUIDFetcher.getUUIDOf(sender.getName())); - playerName = player.getName(); - } catch (Exception e) { - playerName = "ConsoleNotPlayerErr"; - } - } - return playerName; + return DataUtils.getPlayerDisplayname(args, sender); } } diff --git a/src/com/djrapitops/plan/command/commands/SearchCommand.java b/src/com/djrapitops/plan/command/commands/SearchCommand.java new file mode 100644 index 000000000..c4825db9d --- /dev/null +++ b/src/com/djrapitops/plan/command/commands/SearchCommand.java @@ -0,0 +1,89 @@ +package com.djrapitops.plan.command.commands; + +import com.djrapitops.plan.Plan; +import com.djrapitops.plan.command.CommandType; +import com.djrapitops.plan.command.SubCommand; +import com.djrapitops.plan.command.utils.DataFormatUtils; +import com.djrapitops.plan.command.utils.DataUtils; +import static com.palmergames.bukkit.towny.Towny.plugin; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import static org.bukkit.Bukkit.getOfflinePlayer; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +public class SearchCommand extends SubCommand { + + private final Plan plugin; + + public SearchCommand(Plan plugin) { + super("search", "plan.search", "Inspect specific data /plan [-p]", CommandType.CONSOLE_WITH_ARGUMENTS); + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { + boolean playerFirst = false; + for (String arg : args) { + if (arg.equals("-p")) { + playerFirst = true; + } + } + Set matchingPlayers; + if (playerFirst) { + String[] playername = new String[1]; + playername[0] = args[0]; + matchingPlayers = DataUtils.getMatchingDisplaynames(playername, sender, false); + } else { + matchingPlayers = DataUtils.getMatchingDisplaynames(args, sender, false); + } + args = DataFormatUtils.parseSearchArgs(args); + HashMap> data = DataUtils.getTotalData(matchingPlayers); + if (this.plugin.getHooks().isEmpty()) { + this.plugin.logError("noHookedPluginsError on SearchCommand"); + this.plugin.logToFile("SEARCH\nnoHookedPluginsError on SearchCommand"); + + return false; + } + + Date refreshDate = new Date(); + HashMap> dataLists = new HashMap<>(); + for (UUID key : data.keySet()) { + OfflinePlayer p = getOfflinePlayer(key); + HashMap dataMap = data.get(key); + if (!dataMap.isEmpty()) { + dataMap = DataFormatUtils.removeExtraDataPointsSearch(dataMap, args); + } + if (dataMap.isEmpty()) { + dataMap.put("ERR-NO RESULTS", "No results were found."); + plugin.logToFile("SEARCH-Results\nNo results were found for: " + p.getName() + Arrays.toString(args)); + } + dataLists.put(p.getName(), DataFormatUtils.turnDataHashMapToSortedListOfArrays(dataMap)); + } + + ChatColor operatorColor = ChatColor.DARK_GREEN; + ChatColor textColor = ChatColor.GRAY; + + //header + sender.sendMessage(textColor + "-- [" + operatorColor + "PLAN - Search results: took " + DataFormatUtils.formatTimeAmountSinceDate(refreshDate, new Date()) + textColor + "] --"); + + for (String playerName : dataLists.keySet()) { + sender.sendMessage(textColor + "Results for: " + playerName); + for (String[] dataString : dataLists.get(playerName)) { + sender.sendMessage("" + operatorColor + dataString[0].charAt(4) + dataString[0].toLowerCase().substring(5) + ": " + textColor + dataString[1]); + } + } + if (dataLists.isEmpty()) { + sender.sendMessage(operatorColor + "No results for " + textColor + Arrays.toString(args) + operatorColor + "."); + } + sender.sendMessage(textColor + "-- o --"); + return true; + } +} diff --git a/src/com/djrapitops/plan/command/hooks/AdvancedAchievementsHook.java b/src/com/djrapitops/plan/command/hooks/AdvancedAchievementsHook.java index 947b3dc54..7e10f78d7 100644 --- a/src/com/djrapitops/plan/command/hooks/AdvancedAchievementsHook.java +++ b/src/com/djrapitops/plan/command/hooks/AdvancedAchievementsHook.java @@ -5,6 +5,7 @@ import com.djrapitops.plan.UUIDFetcher; import com.hm.achievement.AdvancedAchievements; import com.hm.achievement.category.MultipleAchievements; import com.hm.achievement.category.NormalAchievements; +import java.util.Arrays; import java.util.HashMap; import java.util.UUID; import static org.bukkit.Bukkit.getPlayer; @@ -22,7 +23,7 @@ public class AdvancedAchievementsHook implements Hook { this.plugin = plugin; this.aAPlugin = getPlugin(AdvancedAchievements.class); // Version was important because 4.0.3 added required method for Offline players - String[] aAVersion = aAPlugin.getDescription().getVersion().split("."); + String[] aAVersion = aAPlugin.getDescription().getVersion().split("\\."); try { double versionNumber = Double.parseDouble(aAVersion[0] + "." + aAVersion[1] + aAVersion[2]); if (versionNumber >= 4.03) { @@ -42,7 +43,8 @@ public class AdvancedAchievementsHook implements Hook { plugin.logError("Advanced Achievements 4.0.3 or above required for Offline players"); } } catch (Exception e2) { - plugin.logToFile("AAHOOK\nError getting version number.\n" + e2); + plugin.logToFile("AAHOOK\nError getting version number.\n" + e2+"\n"+e+"\n" + +aAPlugin.getDescription().getVersion()+"\n"+Arrays.toString(aAVersion)); } } // Get total number of Achievements diff --git a/src/com/djrapitops/plan/command/utils/DataFormatUtils.java b/src/com/djrapitops/plan/command/utils/DataFormatUtils.java index dc79a6c76..607fe98d7 100644 --- a/src/com/djrapitops/plan/command/utils/DataFormatUtils.java +++ b/src/com/djrapitops/plan/command/utils/DataFormatUtils.java @@ -1,8 +1,8 @@ - package com.djrapitops.plan.command.utils; import com.djrapitops.plan.Plan; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -11,7 +11,7 @@ import java.util.List; import static org.bukkit.plugin.java.JavaPlugin.getPlugin; public class DataFormatUtils { - + public static HashMap removeExtraDataPoints(HashMap data) throws NumberFormatException { List remove = new ArrayList<>(); Plan plugin = getPlugin(Plan.class); @@ -112,25 +112,26 @@ public class DataFormatUtils { } return data; } + // Creates a new Date with Epoch second and returns Date and Time String public static String formatTimeStamp(String string) throws NumberFormatException { long ms = Long.parseLong(string); Date sfd = new Date(ms); return ("" + sfd).substring(4, 19); } - + // Formats Time Since (0 -> string) public static String formatTimeAmount(String string) throws NumberFormatException { long ms = Long.parseLong(string); return turnMsLongToString(ms); } - + // Formats Time Difference String before -> Date now public static String formatTimeAmountSinceString(String string, Date date) throws NumberFormatException { long ms = (date.toInstant().getEpochSecond() * 1000) - Long.parseLong(string); return turnMsLongToString(ms); } - + // Formats Time Difference Date before -> Date now public static String formatTimeAmountSinceDate(Date before, Date now) throws NumberFormatException { long ms = (now.toInstant().getEpochSecond() * 1000) - (before.toInstant().getEpochSecond() * 1000); @@ -160,6 +161,9 @@ public class DataFormatUtils { if (seconds != 0) { returnValue += seconds + "s"; } + if (returnValue.isEmpty()) { + returnValue += "< 1s"; + } return returnValue; } @@ -184,7 +188,7 @@ public class DataFormatUtils { } return returnString; } - + // Sorts HashMap into Sorted List of Arrays public static List turnDataHashMapToSortedListOfArrays(HashMap data) { List dataList = new ArrayList<>(); @@ -198,4 +202,87 @@ public class DataFormatUtils { }); return dataList; } + + public static HashMap removeExtraDataPointsSearch(HashMap dataMap, String[] args) { + if (args.length <= 1) { + return removeExtraDataPoints(dataMap); + } + HashMap returnMap = new HashMap<>(); + String errors = "FORMAT-SEARCH\n"; + for (String key : dataMap.keySet()) { + for (String arg : args) { + try { + if (key.toLowerCase().contains(arg.toLowerCase())) { + returnMap.put(key, dataMap.get(key)); + } + } catch (Exception e) { + if (!errors.contains(Arrays.toString(args))) { + errors += Arrays.toString(args)+"\n"; + } + errors += (e + "\n" + key + " " + arg + "\n"); + } + } + } + if (!errors.equals("FORMAT-SEARCH\n")) { + Plan plugin = getPlugin(Plan.class); + plugin.logToFile(errors); + } + return removeExtraDataPoints(returnMap); + } + + public static String[] parseSearchArgs(String[] args) { + String[] aacTerms = {"aac", "advanced", "achiev"}; + String[] svoTerms = {"svo", "superb", "vote"}; + String[] ontTerms = {"ont", "onoime", "time"}; + String[] ecoTerms = {"eco", "money", "bal"}; + String[] towTerms = {"tow", "town", "nation", "res", "plot", "perm"}; + + List aac = new ArrayList<>(); + List svo = new ArrayList<>(); + List ont = new ArrayList<>(); + List eco = new ArrayList<>(); + List tow = new ArrayList<>(); + + aac.addAll(Arrays.asList(aacTerms)); + svo.addAll(Arrays.asList(svoTerms)); + ont.addAll(Arrays.asList(ontTerms)); + eco.addAll(Arrays.asList(ecoTerms)); + tow.addAll(Arrays.asList(towTerms)); + String[] returnArray = new String[args.length]; + argloop: + for (int i = 0; i < args.length; i++) { + for (String s : aac) { + if (args[i].toLowerCase().contains(s)) { + returnArray[i] = "AAC"; + continue argloop; + } + } + for (String s : svo) { + if (args[i].toLowerCase().contains(s)) { + returnArray[i] = "SVO"; + continue argloop; + } + } + for (String s : ont) { + if (args[i].toLowerCase().contains(s)) { + returnArray[i] = "ONT"; + continue argloop; + } + } + for (String s : eco) { + if (args[i].toLowerCase().contains(s)) { + returnArray[i] = "ECO"; + continue argloop; + } + } + for (String s : tow) { + if (args[i].toLowerCase().contains(s)) { + returnArray[i] = "TOW"; + continue argloop; + } + } + returnArray[i] = args[i]; + } + return returnArray; + } } diff --git a/src/com/djrapitops/plan/command/utils/DataUtils.java b/src/com/djrapitops/plan/command/utils/DataUtils.java index c70519f95..95240e5aa 100644 --- a/src/com/djrapitops/plan/command/utils/DataUtils.java +++ b/src/com/djrapitops/plan/command/utils/DataUtils.java @@ -1,6 +1,7 @@ package com.djrapitops.plan.command.utils; import com.djrapitops.plan.Plan; +import com.djrapitops.plan.UUIDFetcher; import com.djrapitops.plan.command.hooks.AdvancedAchievementsHook; import java.io.File; import java.util.ArrayList; @@ -9,9 +10,12 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Scanner; +import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import static org.bukkit.plugin.java.JavaPlugin.getPlugin; public class DataUtils { @@ -43,11 +47,11 @@ public class DataUtils { } // Returns data HashMaps for all pplayers in a HashMap. - public static HashMap> getTotalData() { + public static HashMap> getTotalData(Set ofPlayers) { HashMap> playerData = new HashMap<>(); List players = new ArrayList<>(); - players.addAll(Arrays.asList(Bukkit.getOfflinePlayers())); + players.addAll(ofPlayers); players.parallelStream() .filter((player) -> (playerData.get(player.getUniqueId()) == null)) .forEach((player) -> { @@ -190,4 +194,51 @@ public class DataUtils { } return DataFormatUtils.formatAnalyzed(analyzedData); } + + public static String getPlayerDisplayname(String[] args, CommandSender sender) { + String playerName = ""; + Plan plugin = getPlugin(Plan.class); + if (args.length > 0) { + if ((args[0].equals("-a")) || (args[0].equals("-r"))) { + playerName = "ArgumentGivenError"; + plugin.log("No username given, returned empty username."); + + plugin.logToFile("INSPECT-GETNAME\nNo username given, returned empty username.\n" + args[0]); + + } else if (sender.hasPermission("plan.inspect.other") || !(sender instanceof Player)) { + playerName = args[0]; + } + } else { + try { + Player player = plugin.getServer().getPlayer(UUIDFetcher.getUUIDOf(sender.getName())); + playerName = player.getName(); + } catch (Exception e) { + playerName = "ConsoleNotPlayerErr"; + } + } + return playerName; + } + + public static Set getMatchingDisplaynames(String[] args, CommandSender sender, boolean all) { + List players = new ArrayList<>(); + players.addAll(Arrays.asList(Bukkit.getOfflinePlayers())); + Set matches = new HashSet<>(); + if (all) { + matches.addAll(players); + } else { + List searchTerms = new ArrayList<>(); + searchTerms.addAll(Arrays.asList(args)); + + players.parallelStream().forEach((p) -> { + searchTerms.stream().filter((searchTerm) -> (p.getName().toLowerCase().contains(searchTerm.toLowerCase()))).forEach((_item) -> { + matches.add(p); + }); + }); + } + return matches; + } + + public static Set getMatchingDisplaynames(boolean b) { + return getMatchingDisplaynames(new String[0], null, true); + } } diff --git a/src/plugin.yml b/src/plugin.yml index 596119c77..41c80c5d5 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -11,10 +11,12 @@ commands: description: inspect player data analyze: usage: /plan analyze - description: analyze all players' data, add -r to refresh analysis. + description: analyze all players' data, add -refresh to refresh analysis. reload: usage: /plan reload description: reload plugin config + search: + usage: /plan -p add -p to make not search playername softdepend: - OnTime @@ -44,4 +46,7 @@ permissions: default: false plan.reload: description: Allows to reload plugin config + default: true + plan.search: + description: Allows search default: true \ No newline at end of file