diff --git a/build.gradle b/build.gradle index ad5c44a..95ef388 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } group 'sh.okx' -version '3.8.2' +version '3.9-beta.1' repositories { mavenCentral() @@ -27,7 +27,7 @@ repositories { dependencies { testImplementation group: 'junit', name: 'junit', version: '4.12' compileOnly 'org.jetbrains:annotations:16.0.2' - implementation 'org.spigotmc:spigot-api:1.15.2-R0.1-SNAPSHOT' + implementation 'org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT' implementation('com.github.Realizedd:TokenManager:3.2.4') { transitive = false } @@ -35,7 +35,7 @@ dependencies { implementation('com.github.MilkBowl:VaultAPI:1.7') { exclude group: 'org.bukkit' } - implementation 'me.clip:placeholderapi:2.9.2' + implementation 'me.clip:placeholderapi:2.10.6' implementation 'com.hm.achievement:advanced-achievements-api:1.1.0' implementation('com.github.mcMMO-Dev:mcMMO:601297') { exclude group: 'com.sk89q.worldguard' diff --git a/src/main/java/sh/okx/rankup/RankupHelper.java b/src/main/java/sh/okx/rankup/RankupHelper.java index 1f16bb4..6d8b776 100644 --- a/src/main/java/sh/okx/rankup/RankupHelper.java +++ b/src/main/java/sh/okx/rankup/RankupHelper.java @@ -55,16 +55,17 @@ public class RankupHelper { .send(player); } - public void doPrestige(Player player, Prestige prestige) { - prestige.runCommands(player); + public void doPrestige(Player player, RankElement prestige) { + Prestige rank = prestige.getRank(); + rank.runCommands(player); - permissions.removeGroup(player.getUniqueId(), prestige.getFrom()); - permissions.addGroup(player.getUniqueId(), prestige.getTo()); + permissions.removeGroup(player.getUniqueId(), rank.getFrom()); + permissions.addGroup(player.getUniqueId(), rank.getTo()); - if (prestige.getRank() != null) { - permissions.removeGroup(player.getUniqueId(), prestige.getRank()); + if (rank.getRank() != null) { + permissions.removeGroup(player.getUniqueId(), rank.getRank()); } - permissions.addGroup(player.getUniqueId(), prestige.getNext()); + permissions.addGroup(player.getUniqueId(), prestige.getNext().getRank().getRank()); } public void sendPrestigeMessages(Player player, RankElement prestige) { @@ -179,7 +180,7 @@ public class RankupHelper { prestige.applyRequirements(player); applyCooldown(player); - doPrestige(player, prestige); + doPrestige(player, rankElement); sendPrestigeMessages(player, rankElement); } diff --git a/src/main/java/sh/okx/rankup/RankupPlugin.java b/src/main/java/sh/okx/rankup/RankupPlugin.java index 4ef966a..f656e13 100644 --- a/src/main/java/sh/okx/rankup/RankupPlugin.java +++ b/src/main/java/sh/okx/rankup/RankupPlugin.java @@ -55,6 +55,8 @@ import java.util.function.Supplier; public class RankupPlugin extends JavaPlugin { + public static final int CONFIG_VERSION = 8; + @Getter private GroupProvider permissions; @Getter @@ -78,11 +80,10 @@ public class RankupPlugin extends JavaPlugin { private RankupHelper helper; private AutoRankup autoRankup; private String errorMessage; - private UpdateNotifier notifier; @Override public void onEnable() { - notifier = new UpdateNotifier(new VersionChecker(this)); + UpdateNotifier notifier = new UpdateNotifier(new VersionChecker(this)); reload(true); @@ -99,6 +100,10 @@ public class RankupPlugin extends JavaPlugin { })); metrics.addCustomChart(new Metrics.SimplePie("prestige", () -> config.getBoolean("prestige") ? "enabled" : "disabled")); + metrics.addCustomChart(new Metrics.SimplePie("permission-rankup", + () -> config.getBoolean("permission-rankup") ? "enabled" : "disabled")); + metrics.addCustomChart(new Metrics.SimplePie("notify-update", + () -> config.getBoolean("notify-update") ? "enabled" : "disabled")); if (config.getBoolean("ranks")) { getCommand("ranks").setExecutor(new RanksCommand(this)); @@ -162,7 +167,7 @@ public class RankupPlugin extends JavaPlugin { autoRankup.runTaskTimer(this, time, time); } - if (config.getInt("version") < 7) { + if (config.getInt("version") < CONFIG_VERSION) { getLogger().severe("You are using an outdated config!"); getLogger().severe("This means that some things might not work!"); getLogger().severe("To update, please rename ALL your config files (or the folder they are in),"); diff --git a/src/main/java/sh/okx/rankup/commands/InfoCommand.java b/src/main/java/sh/okx/rankup/commands/InfoCommand.java index b1793ba..1f58441 100644 --- a/src/main/java/sh/okx/rankup/commands/InfoCommand.java +++ b/src/main/java/sh/okx/rankup/commands/InfoCommand.java @@ -3,10 +3,13 @@ package sh.okx.rankup.commands; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.util.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.prestige.Prestiges; @@ -15,7 +18,9 @@ import sh.okx.rankup.ranks.RankElement; import sh.okx.rankup.ranks.Rankups; import sh.okx.rankup.util.UpdateNotifier; -public class InfoCommand implements CommandExecutor { +import java.util.*; + +public class InfoCommand implements TabExecutor { private final RankupPlugin plugin; private final UpdateNotifier notifier; @@ -95,7 +100,7 @@ public class InfoCommand implements CommandExecutor { return true; } - plugin.getHelper().doPrestige(player, prestige); + plugin.getHelper().doPrestige(player, rankElement); plugin.getHelper().sendPrestigeMessages(player, rankElement); sender.sendMessage(ChatColor.GREEN + "Successfully forced " + ChatColor.GOLD + player.getName() @@ -105,7 +110,87 @@ public class InfoCommand implements CommandExecutor { + ChatColor.GREEN + " to " + ChatColor.GOLD + prestige.getTo()); return true; } else if(args[0].equalsIgnoreCase("rankdown") && sender.hasPermission("rankup.force")) { + if (args.length < 2) { + sender.sendMessage(ChatColor.YELLOW + "Usage: /" + label + " rankdown "); + return true; + } + Player player = Bukkit.getPlayer(args[1]); + if (player == null) { + sender.sendMessage(ChatColor.YELLOW + "Player not found."); + return true; + } + + RankElement currentRankElement = plugin.getRankups().getByPlayer(player); + if (currentRankElement == null) { + sender.sendMessage(ChatColor.YELLOW + "That player is not in any rankup groups."); + return true; + } + Rank currentRank = currentRankElement.getRank(); + + if (plugin.getRankups().getFirst().equals(currentRank)) { + sender.sendMessage(ChatColor.YELLOW + "That player is in the first rank and cannot be ranked down."); + + } + + RankElement prevRankElement = plugin.getRankups().getTree().getFirst(); + while(prevRankElement.hasNext() && !prevRankElement.getNext().getRank().equals(currentRank)) { + prevRankElement = prevRankElement.getNext(); + } + + if (!prevRankElement.hasNext()) { + sender.sendMessage(ChatColor.YELLOW + "Could not match previous rank."); + } + Rank prevRank = prevRankElement.getRank(); + + if (prevRankElement.getRank() != null) { + plugin.getPermissions().removeGroup(player.getUniqueId(), currentRank.getRank()); + } + plugin.getPermissions().addGroup(player.getUniqueId(), prevRank.getRank()); + + sender.sendMessage(ChatColor.GREEN + "Successfully forced " + + ChatColor.GOLD + player.getName() + + ChatColor.GREEN + " to rank down from " + ChatColor.GOLD + currentRank.getRank() + + ChatColor.GREEN + " to " + ChatColor.GOLD + prevRank.getRank()); + return true; + } else if (args[0].equalsIgnoreCase("placeholders") && sender.hasPermission("rankup.admin")) { + sender.sendMessage("--- Rankup placeholders ---"); + if (args.length > 1 && args[1].equalsIgnoreCase("status")) { + for (Rank rank : plugin.getRankups().getTree()) { + String placeholder = "status_" + rank.getRank(); + sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().onPlaceholderRequest(sender instanceof Player ? (Player) sender : null, placeholder)); + } + return true; + } + + String[] placeholders = new String[] { + "prestige_money", + "prestige_money_formatted", + "prestige_percent_left_formatted", + "prestige_percent_done_formatted", + "money_formatted", + "money_left_formatted", + "percent_left_formatted", + "percent_done_formatted", + "current_prestige", + "next_prestige", + "current_rank", + "next_rank", + }; + for (String placeholder : placeholders) { + sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().onPlaceholderRequest(sender instanceof Player ? (Player) sender : null, placeholder)); + } + return true; + } else if (args[0].equalsIgnoreCase("tree") && sender.hasPermission("rankup.admin")) { + RankElement element = plugin.getRankups().getTree().getFirst(); + while (element.hasNext()) { + Rank rank = element.getRank(); + RankElement next = element.getNext(); + Rank nextRank = next.getRank(); + sender.sendMessage(rank.getRank() + " (" + rank.getNext() + ") -> " + nextRank.getRank() + " (" + nextRank.getNext() + ")"); + element = next; + } + return true; } } @@ -132,4 +217,37 @@ public class InfoCommand implements CommandExecutor { return true; } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + if (args.length == 1) { + List list = new ArrayList<>(); + if (sender.hasPermission("rankup.reload")) { + list.add("reload"); + } + if (sender.hasPermission("rankup.force")) { + list.add("forcerankup"); + list.add("forceprestige"); + list.add("rankdown"); + } + return StringUtil.copyPartialMatches(args[0], list, new ArrayList<>()); + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("forcerankup") && sender.hasPermission("rankup.force")) { + return StringUtil.copyPartialMatches(args[1], players(), new ArrayList<>()); + } else if (args[0].equalsIgnoreCase("forceprestige") && sender.hasPermission("rankup.force")) { + return StringUtil.copyPartialMatches(args[1], players(), new ArrayList<>()); + } else if (args[0].equalsIgnoreCase("rankdown") && sender.hasPermission("rankup.force")) { + return StringUtil.copyPartialMatches(args[1], players(), new ArrayList<>()); + } + } + return Collections.emptyList(); + } + + private Iterable players() { + Set players = new HashSet<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + players.add(player.getName()); + } + return players; + } } diff --git a/src/main/java/sh/okx/rankup/gui/Gui.java b/src/main/java/sh/okx/rankup/gui/Gui.java index d1a6257..40bf4f9 100644 --- a/src/main/java/sh/okx/rankup/gui/Gui.java +++ b/src/main/java/sh/okx/rankup/gui/Gui.java @@ -99,7 +99,6 @@ public class Gui implements InventoryHolder { meta.setDisplayName(ChatColor.RESET + format(plugin, section.getString("name"), player, oldRank, rank)); } item.setItemMeta(meta); - return item; } diff --git a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java index bbf0d48..f04401e 100644 --- a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java +++ b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java @@ -59,11 +59,30 @@ public class RankupExpansion extends PlaceholderExpansion { } return plugin.formatMoney(Math.max(0, amount)); } else if (params.startsWith("status_")) { - if (rankElement != null && (!rankElement.hasNext() || rank.isIn(player))) { - return getPlaceholder("status-complete"); - } else { - return getPlaceholder("status-incomplete"); + String[] parts = params.split("_", 2); + Rank statusRank = rankups.getByName(parts[1]); + + if (statusRank == null) { + return null; } + if (rank == null) { + return getPlaceholder("status.incomplete"); + } + if (statusRank.equals(rank)) { + return getPlaceholder("status.current"); + } + + // is playerRank before or after statusRank? + for (RankElement element : rankups.getTree().asList()) { + if (element.getRank().equals(statusRank)) { + return getPlaceholder("status.complete"); + } else if (element.getRank().equals(rank)) { + return getPlaceholder("status.incomplete"); + } + } + + // this should not happen + return null; } switch (params) { diff --git a/src/main/java/sh/okx/rankup/ranks/RankTree.java b/src/main/java/sh/okx/rankup/ranks/RankTree.java index 40f0885..aecf12b 100644 --- a/src/main/java/sh/okx/rankup/ranks/RankTree.java +++ b/src/main/java/sh/okx/rankup/ranks/RankTree.java @@ -34,13 +34,14 @@ public class RankTree implements Iterable { private RankElement element = first; @Override public boolean hasNext() { - return element.hasNext(); + return element != null; } @Override public T next() { + T rank = element.getRank(); element = element.getNext(); - return element.getRank(); + return rank; } }; } diff --git a/src/main/java/sh/okx/rankup/requirements/RequirementRegistry.java b/src/main/java/sh/okx/rankup/requirements/RequirementRegistry.java index d74800f..6d790d1 100644 --- a/src/main/java/sh/okx/rankup/requirements/RequirementRegistry.java +++ b/src/main/java/sh/okx/rankup/requirements/RequirementRegistry.java @@ -6,7 +6,7 @@ import java.util.Objects; import java.util.Set; public class RequirementRegistry { - private Set requirements = new HashSet<>(); + private final Set requirements = new HashSet<>(); public void addRequirement(Requirement requirement) { requirements.add(requirement); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index fadf4d8..53dfc2c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,5 @@ # this is used for letting you know that you need to update/change your config file -version: 7 +version: 8 # the locale to use for messages # all messages can be customised but this allows you to @@ -52,7 +52,7 @@ cooldown: 1 # if enabled, players can run /maxrankup to rankup as many times as possible, # before they fail the requirements for the next rank. -# the permission rankup.maxrankup is used for this command, but it is usually given by default. +# the permission rankup.maxrankup is used for this command, but it is given by default. # note that /maxrankup, if enabled, has no confirmation. max-rankup: # You must restart your server if you enable or disable /maxrankup! @@ -85,8 +85,10 @@ placeholders: # used in the next_rank and next_prestige placeholders when a player is at the highest rank or prestige highest-rank: "None" # used in the %rankup_status_[rank]% placeholders - status-complete: "Complete" - status-incomplete: "Incomplete" + status: + complete: "Complete" + current: "Current" + incomplete: "Incomplete" # what to shorten money by. # ie 1000 -> 1k @@ -94,7 +96,7 @@ placeholders: # for each entry here, it counts as increasing by a factor of 1,000 # the first represents thousands (1,000) then millions (1,000,000) then billions (1,000,000,000) etc. shorten: -- 'k' +- 'K' - 'M' - 'B' - 'T' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 11b807f..7ed22d9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,7 +11,6 @@ commands: permission: rankup.rankup description: Rankup. rankup3: - permission: rankup3.info description: View Rankup version and perform some administrative commands. # support the old command aliases: [pru] @@ -30,7 +29,6 @@ commands: permissions: rankup.*: children: - rankup.info: true rankup.rankup: true rankup.admin: true rankup.ranks: true @@ -49,8 +47,6 @@ permissions: # if a player receives notifications to update rankup when they log in. rankup.notify: true default: op - rankup.info: - default: true rankup.rankup: default: true rankup.ranks: