From 2c5a631b2e35ed7b8013a79e41628641e8fd9172 Mon Sep 17 00:00:00 2001 From: okx-code Date: Sun, 24 Oct 2021 22:54:04 +0100 Subject: [PATCH] 3.13 Fix ranks not replacing for console Some messaging refactoring Add "shortmoney" filter Add TOML support for rankups.yml/rankups.toml --- build.gradle | 12 ++-- src/main/java/sh/okx/rankup/RankupHelper.java | 20 +++--- src/main/java/sh/okx/rankup/RankupPlugin.java | 39 ++++++----- .../okx/rankup/commands/PrestigesCommand.java | 4 -- .../java/sh/okx/rankup/messages/Message.java | 4 +- .../okx/rankup/messages/MessageBuilder.java | 9 +-- .../rankup/messages/NullMessageBuilder.java | 12 +++- .../rankup/messages/StringMessageBuilder.java | 6 ++ .../java/sh/okx/rankup/messages/Variable.java | 10 +-- .../pebble/InvalidRequirementException.java | 22 ++++++ .../messages/pebble/PebbleMessageBuilder.java | 40 +++++------ .../rankup/messages/pebble/RankContext.java | 8 ++- .../okx/rankup/placeholders/Placeholders.java | 19 ++++++ .../rankup/placeholders/RankupExpansion.java | 8 +-- .../sh/okx/rankup/prestige/Prestiges.java | 17 ++++- .../java/sh/okx/rankup/ranks/RankList.java | 33 +++------ src/main/java/sh/okx/rankup/ranks/Rankup.java | 26 ++++--- .../java/sh/okx/rankup/ranks/Rankups.java | 16 ++++- .../requirements/RankRequirementsFactory.java | 17 +++++ .../serialization/PrestigeSerialized.java | 25 +++++++ .../rankup/serialization/RankSerialized.java | 31 +++++++++ .../serialization/ShadowDeserializer.java | 67 +++++++++++++++++++ .../serialization/YamlDeserializer.java | 57 ++++++++++++++++ .../okx/rankup/text/LegacyTextProcessor.java | 6 +- .../okx/rankup/text/TextProcessorBuilder.java | 6 +- .../rankup/text/pebble/MoneyShortFilter.java | 38 +++++++++++ .../okx/rankup/text/pebble/PebbleOptions.java | 11 --- .../text/pebble/PebbleTextProcessor.java | 38 +++++++++-- src/main/resources/config.yml | 1 + src/main/resources/locale/en.yml | 7 +- src/main/resources/locale/es.yml | 3 +- src/main/resources/locale/fr.yml | 3 +- src/main/resources/locale/it.yml | 1 - src/main/resources/locale/nl.yml | 3 +- src/main/resources/locale/pt_br.yml | 3 +- src/main/resources/locale/ru.yml | 1 - src/main/resources/locale/zh_cn.yml | 1 - src/main/resources/rankups.yml | 4 +- .../sh/okx/rankup/RankupCommandsTest.java | 5 ++ .../CommandInfoTest.java} | 5 +- .../rankup/prestige/BrokenPrestigeTest.java | 25 +++++++ .../sh/okx/rankup/providers/TestEconomy.java | 2 +- .../java/sh/okx/rankup/toml/TomlTest.java | 55 +++++++++++++++ src/test/resources/brokenprestige/config.yml | 36 ++++++++++ src/test/resources/brokenprestige/rankups.yml | 10 +++ src/test/resources/toml/rankups.toml | 25 +++++++ 46 files changed, 629 insertions(+), 162 deletions(-) create mode 100644 src/main/java/sh/okx/rankup/messages/pebble/InvalidRequirementException.java create mode 100644 src/main/java/sh/okx/rankup/serialization/PrestigeSerialized.java create mode 100644 src/main/java/sh/okx/rankup/serialization/RankSerialized.java create mode 100644 src/main/java/sh/okx/rankup/serialization/ShadowDeserializer.java create mode 100644 src/main/java/sh/okx/rankup/serialization/YamlDeserializer.java create mode 100644 src/main/java/sh/okx/rankup/text/pebble/MoneyShortFilter.java delete mode 100644 src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java create mode 100644 src/test/java/sh/okx/rankup/RankupCommandsTest.java rename src/test/java/sh/okx/rankup/{RankupCommandTest.java => commands/CommandInfoTest.java} (90%) create mode 100644 src/test/java/sh/okx/rankup/prestige/BrokenPrestigeTest.java create mode 100644 src/test/java/sh/okx/rankup/toml/TomlTest.java create mode 100644 src/test/resources/brokenprestige/config.yml create mode 100644 src/test/resources/brokenprestige/rankups.yml create mode 100644 src/test/resources/toml/rankups.toml diff --git a/build.gradle b/build.gradle index 843a173..f73a36d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'sh.okx' -version '3.12.2' +version '3.13' java { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -29,15 +29,15 @@ repositories { } dependencies { - testImplementation("org.junit.platform:junit-platform-launcher:1.7.2") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.2") + testImplementation 'org.junit.platform:junit-platform-launcher:1.8.1' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1' testImplementation 'com.github.MockBukkit:MockBukkit:04889261630cd6f5aaebd86a576bbcd12c442ea7' implementation group: 'org.slf4j', name: 'slf4j-nop', version: '1.7.30' implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30' - compileOnly 'org.jetbrains:annotations:16.0.2' - compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT' + compileOnly 'org.jetbrains:annotations:22.0.0' + compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT' compileOnly('com.github.Realizedd:TokenManager:3.2.4') { transitive = false } @@ -59,6 +59,7 @@ dependencies { implementation ('io.pebbletemplates:pebble:3.1.5') { exclude group: 'org.slf4j' } + implementation 'com.electronwill.night-config:toml:3.6.4' } artifacts { @@ -68,6 +69,7 @@ artifacts { shadowJar { archiveClassifier.set('') minimize() + relocate 'org.slf4j', 'sh.okx.rankup.export.org.slf4j' } // automatically copy the version to plugin.yml diff --git a/src/main/java/sh/okx/rankup/RankupHelper.java b/src/main/java/sh/okx/rankup/RankupHelper.java index 55807bf..d96ec20 100644 --- a/src/main/java/sh/okx/rankup/RankupHelper.java +++ b/src/main/java/sh/okx/rankup/RankupHelper.java @@ -10,7 +10,6 @@ import sh.okx.rankup.events.PlayerPrestigeEvent; import sh.okx.rankup.events.PlayerRankupEvent; import sh.okx.rankup.hook.GroupProvider; import sh.okx.rankup.messages.Message; -import sh.okx.rankup.messages.Variable; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.prestige.Prestiges; import sh.okx.rankup.ranks.Rank; @@ -110,9 +109,7 @@ public class RankupHelper { .failIfEmpty() .replacePlayer(player) .replaceRank(rank) - .replaceKey(Variable.SECONDS.toString(), cooldownSeconds) - .replaceKey(Variable.SECONDS_LEFT.toString(), secondsLeft) - .replaceKey(Variable.SECONDS_LEFT.toString().toLowerCase(), secondsLeft) + .replaceSeconds(cooldownSeconds, secondsLeft) .send(player); return true; } @@ -165,9 +162,14 @@ public class RankupHelper { Rank rank = rankElement.getRank(); if (!rankElement.hasNext()) { Prestiges prestiges = plugin.getPrestiges(); - plugin.getMessage( - prestiges == null || !prestiges.getByPlayer(player).hasNext() ? Message.NO_RANKUP - : Message.MUST_PRESTIGE) + Message pMessage = Message.NO_RANKUP; + if (prestiges != null) { + RankElement byPlayer = prestiges.getByPlayer(player); + if (byPlayer != null && byPlayer.hasNext()) { + pMessage = Message.MUST_PRESTIGE; + } + } + plugin.getMessage(pMessage) .failIf(!message) .replacePlayer(player) .replaceRank(rankups.getTree().last().getRank()) @@ -210,8 +212,8 @@ public class RankupHelper { public boolean checkPrestige(Player player, boolean message) { Prestiges prestiges = plugin.getPrestiges(); RankElement prestigeElement = prestiges.getByPlayer(player); - if (prestigeElement == null || !prestigeElement.getRank() - .isEligible(player)) { // check if in ladder + if (prestigeElement == null + || !prestigeElement.getRank().isEligible(player)) { // check if in ladder plugin.getMessage(Message.NOT_HIGH_ENOUGH) .failIf(!message) .replacePlayer(player) diff --git a/src/main/java/sh/okx/rankup/RankupPlugin.java b/src/main/java/sh/okx/rankup/RankupPlugin.java index c413c48..aa25570 100644 --- a/src/main/java/sh/okx/rankup/RankupPlugin.java +++ b/src/main/java/sh/okx/rankup/RankupPlugin.java @@ -1,6 +1,9 @@ package sh.okx.rankup; +import com.electronwill.nightconfig.toml.TomlFormat; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -80,6 +83,9 @@ import sh.okx.rankup.requirements.requirement.towny.TownyResidentRequirement; import sh.okx.rankup.requirements.requirement.votingplugin.VotingPluginPointsDeductibleRequirement; import sh.okx.rankup.requirements.requirement.votingplugin.VotingPluginPointsRequirement; import sh.okx.rankup.requirements.requirement.votingplugin.VotingPluginVotesRequirement; +import sh.okx.rankup.serialization.RankSerialized; +import sh.okx.rankup.serialization.ShadowDeserializer; +import sh.okx.rankup.serialization.YamlDeserializer; import sh.okx.rankup.util.UpdateNotifier; import sh.okx.rankup.util.VersionChecker; @@ -315,7 +321,7 @@ public class RankupPlugin extends JavaPlugin { prestiges = null; } - rankups = new Rankups(this, loadConfig("rankups.yml")); + rankups = new Rankups(this, loadRankupConfig("rankups")); // check rankups are not in an infinite loop // rankups.getOrderedList(); @@ -346,6 +352,21 @@ public class RankupPlugin extends JavaPlugin { } } + private List loadRankupConfig(String name) { + File ymlFile = new File(getDataFolder(), name + ".yml"); + File tomlFile = new File(getDataFolder(), name + ".toml"); + if (tomlFile.exists()) { + try { + return ShadowDeserializer.deserialize(TomlFormat.instance().createParser().parse(new FileReader(tomlFile))); + } catch (FileNotFoundException ignored) { + } + } + if (!ymlFile.exists()) { + saveResource(ymlFile.getName(), false); + } + return YamlDeserializer.deserialize(YamlConfiguration.loadConfiguration(ymlFile)); + } + private FileConfiguration loadConfig(String name) { File file = new File(getDataFolder(), name); if (!file.exists()) { @@ -418,22 +439,6 @@ public class RankupPlugin extends JavaPlugin { economy = economyProvider.getEconomy(); } - public String formatMoney(double money) { - List shortened = config.getStringList("shorten"); - String suffix = ""; - - for (int i = shortened.size(); i > 0; i--) { - double value = Math.pow(10, 3 * i); - if (money >= value) { - money /= value; - suffix = shortened.get(i - 1); - break; - } - } - - return placeholders.getMoneyFormat().format(money) + suffix; - } - public ConfigurationSection getSection(Rank rank, String path) { ConfigurationSection rankSection = rank.getSection(); if (rankSection == null || !rankSection.isConfigurationSection(path)) { diff --git a/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java b/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java index 39b359a..83a0e38 100644 --- a/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java +++ b/src/main/java/sh/okx/rankup/commands/PrestigesCommand.java @@ -8,7 +8,6 @@ import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.messages.Message; import sh.okx.rankup.messages.MessageBuilder; -import sh.okx.rankup.messages.Variable; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.prestige.Prestiges; import sh.okx.rankup.ranks.RankElement; @@ -42,9 +41,6 @@ public class PrestigesCommand implements CommandExecutor { } else { MessageBuilder builder = plugin .getMessage(sender, message, prestige.getRank(), next.getRank()); - if (prestiges.getFirst().equals(prestige.getRank())) { - builder.replaceKey(Variable.OLD_RANK.toString(), prestige.getRank().getFrom()); - } builder.send(sender); } prestige = next; diff --git a/src/main/java/sh/okx/rankup/messages/Message.java b/src/main/java/sh/okx/rankup/messages/Message.java index dc61eaa..784d9e5 100644 --- a/src/main/java/sh/okx/rankup/messages/Message.java +++ b/src/main/java/sh/okx/rankup/messages/Message.java @@ -4,6 +4,7 @@ import lombok.Getter; public enum Message { NOT_IN_LADDER("not-in-ladder"), + NOT_HIGH_ENOUGH("not-high-enough"), REQUIREMENTS_NOT_MET("rankup.requirements-not-met"), NO_RANKUP("rankup.no-rankup"), SUCCESS_PUBLIC("rankup.success-public"), @@ -26,11 +27,10 @@ public enum Message { COOLDOWN_SINGULAR("rankup.cooldown.singular"), COOLDOWN_PLURAL("rankup.cooldown.plural"), MUST_PRESTIGE("rankup.must-prestige"), - NOT_HIGH_ENOUGH("not-high-enough"), PRESTIGE_SUCCESS_PUBLIC("prestige.success-public"), PRESTIGE_SUCCESS_PRIVATE("prestige.success-private"), PRESTIGE_CONFIRMATION("prestige.confirmation"), - INVALID_RANKUP("invalid-rankup"); + ; @Getter private final String name; diff --git a/src/main/java/sh/okx/rankup/messages/MessageBuilder.java b/src/main/java/sh/okx/rankup/messages/MessageBuilder.java index 859627e..379898d 100644 --- a/src/main/java/sh/okx/rankup/messages/MessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/MessageBuilder.java @@ -9,6 +9,7 @@ public interface MessageBuilder { MessageBuilder replacePlayer(CommandSender sender); MessageBuilder replaceRank(Rank rank); MessageBuilder replaceOldRank(Rank rank); + MessageBuilder replaceSeconds(long seconds, long secondsLeft); void send(CommandSender sender); void broadcast(); @@ -16,13 +17,7 @@ public interface MessageBuilder { String toString(); MessageBuilder failIfEmpty(); - default MessageBuilder failIf(boolean b) { - if (b) { - return new NullMessageBuilder(); - } else { - return this; - } - } + MessageBuilder failIf(boolean b); default String toString(Player player) { return toString(); diff --git a/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java index 1912cc5..dbea283 100644 --- a/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/NullMessageBuilder.java @@ -28,6 +28,11 @@ public class NullMessageBuilder implements MessageBuilder { return this; } + @Override + public MessageBuilder replaceSeconds(long seconds, long secondsLeft) { + return null; + } + @Override public void send(CommandSender sender) { @@ -45,6 +50,11 @@ public class NullMessageBuilder implements MessageBuilder { @Override public MessageBuilder failIfEmpty() { - return null; + return this; + } + + @Override + public MessageBuilder failIf(boolean b) { + return this; } } diff --git a/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java index 9a87d6e..5119d45 100644 --- a/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/StringMessageBuilder.java @@ -93,6 +93,12 @@ public class StringMessageBuilder implements MessageBuilder { .replace(Variable.OLD_RANK_NAME, rank.getDisplayName()); } + @Override + public MessageBuilder replaceSeconds(long seconds, long secondsLeft) { + return replace(Variable.SECONDS, seconds) + .replace(Variable.SECONDS_LEFT, secondsLeft); + } + public void send(CommandSender sender) { String msg = message; if (sender instanceof Player && Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { diff --git a/src/main/java/sh/okx/rankup/messages/Variable.java b/src/main/java/sh/okx/rankup/messages/Variable.java index 1ff5bf6..0d3320d 100644 --- a/src/main/java/sh/okx/rankup/messages/Variable.java +++ b/src/main/java/sh/okx/rankup/messages/Variable.java @@ -1,6 +1,6 @@ package sh.okx.rankup.messages; -public enum Variable { +enum Variable { PLAYER, OLD_RANK_NAME, OLD_RANK, @@ -8,14 +8,6 @@ public enum Variable { RANK, FROM, TO, - MONEY, - MONEY_NEEDED, - MONEY_DONE, - AMOUNT, - AMOUNT_NEEDED, - AMOUNT_DONE, - PERCENT_DONE, - PERCENT_LEFT, SECONDS, SECONDS_LEFT } diff --git a/src/main/java/sh/okx/rankup/messages/pebble/InvalidRequirementException.java b/src/main/java/sh/okx/rankup/messages/pebble/InvalidRequirementException.java new file mode 100644 index 0000000..03e8c8d --- /dev/null +++ b/src/main/java/sh/okx/rankup/messages/pebble/InvalidRequirementException.java @@ -0,0 +1,22 @@ +package sh.okx.rankup.messages.pebble; + +import sh.okx.rankup.ranks.Rank; + +public class InvalidRequirementException extends RuntimeException { + private final String requirement; + private final Rank rank; + + public InvalidRequirementException(String requirement, Rank rank) { + super("Invalid requirement: " + requirement + " for rank " + rank.getRank()); + this.requirement = requirement; + this.rank = rank; + } + + public String getRequirement() { + return requirement; + } + + public Rank getRank() { + return rank; + } +} diff --git a/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java b/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java index 4d85186..0110c42 100644 --- a/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java +++ b/src/main/java/sh/okx/rankup/messages/pebble/PebbleMessageBuilder.java @@ -7,17 +7,14 @@ import java.util.Map; import java.util.function.Function; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.messages.MessageBuilder; import sh.okx.rankup.messages.NullMessageBuilder; -import sh.okx.rankup.placeholders.Placeholders; import sh.okx.rankup.prestige.Prestige; import sh.okx.rankup.ranks.Rank; import sh.okx.rankup.text.TextProcessor; import sh.okx.rankup.text.TextProcessorBuilder; -import sh.okx.rankup.text.pebble.PebbleOptions; public class PebbleMessageBuilder implements MessageBuilder { @@ -40,7 +37,6 @@ public class PebbleMessageBuilder implements MessageBuilder { } return ranks; }); - lastMinuteContext.put("player", HumanEntity::getName); } @Override @@ -57,7 +53,9 @@ public class PebbleMessageBuilder implements MessageBuilder { @Override public PebbleMessageBuilder replaceRank(Rank rank) { - lastMinuteContext.put("next", player -> new RankContext(plugin, player, rank)); + Function fun = player -> new RankContext(plugin, player, rank); + context.put("next", fun.apply(null)); // for console + lastMinuteContext.put("next", fun); return this; } @@ -69,10 +67,18 @@ public class PebbleMessageBuilder implements MessageBuilder { } else { object = player -> new RankContext(plugin, player, rank); } + context.put("rank", object.apply(null)); // for console lastMinuteContext.put("rank", object); return this; } + @Override + public MessageBuilder replaceSeconds(long seconds, long secondsLeft) { + context.put("seconds", seconds); + context.put("seconds_left", secondsLeft); + return this; + } + @Override public void send(CommandSender sender) { Player player = null; @@ -102,11 +108,10 @@ public class PebbleMessageBuilder implements MessageBuilder { private TextProcessor processor(Player player) { Map context = getContext(player); - PebbleOptions options = getOptions(); return new TextProcessorBuilder() - .legacy(context, options) + .legacy(context, plugin.getPlaceholders()) .papi(player) - .pebble(context, options) + .pebble(context, plugin.getPlaceholders()) .papi(player) .colour() .create(); @@ -116,7 +121,10 @@ public class PebbleMessageBuilder implements MessageBuilder { Map context = new HashMap<>(this.context); if (player != null) { for (Map.Entry> lastMinute : lastMinuteContext.entrySet()) { - context.putIfAbsent(lastMinute.getKey(), lastMinute.getValue().apply(player)); + context.put(lastMinute.getKey(), lastMinute.getValue().apply(player)); + } + if (!context.containsKey("player")) { + context.put("player", player.getName()); } } return context; @@ -124,17 +132,11 @@ public class PebbleMessageBuilder implements MessageBuilder { @Override public MessageBuilder failIfEmpty() { - if (message.isEmpty()) { - return new NullMessageBuilder(); - } else { - return this; - } + return failIf(message.isEmpty()); } - private PebbleOptions getOptions() { - Placeholders placeholders = plugin.getPlaceholders(); - return new PebbleOptions(placeholders.getMoneyFormat(), - placeholders.getPercentFormat(), - placeholders.getSimpleFormat()); + @Override + public MessageBuilder failIf(boolean b) { + return b ? new NullMessageBuilder() : this; } } diff --git a/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java b/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java index b32ee09..8589647 100644 --- a/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java +++ b/src/main/java/sh/okx/rankup/messages/pebble/RankContext.java @@ -28,11 +28,15 @@ public class RankContext { } public RequirementContext getRequirement(String requirement) { - return new RequirementContext(player, rank.getRequirement(player, requirement)); + Requirement context = rank.getRequirement(player, requirement); + if (context == null) { + throw new InvalidRequirementException(requirement, rank); + } + return new RequirementContext(player, context); } public RequirementContext getRequirement(String requirement, String sub) { - return new RequirementContext(player, rank.getRequirement(player, requirement + "#" + sub)); + return getRequirement(requirement + "#" + sub); } public RequirementContext getReq(String requirement) { diff --git a/src/main/java/sh/okx/rankup/placeholders/Placeholders.java b/src/main/java/sh/okx/rankup/placeholders/Placeholders.java index a6262c6..699bba5 100644 --- a/src/main/java/sh/okx/rankup/placeholders/Placeholders.java +++ b/src/main/java/sh/okx/rankup/placeholders/Placeholders.java @@ -1,6 +1,7 @@ package sh.okx.rankup.placeholders; import java.text.DecimalFormat; +import java.util.List; import lombok.Getter; import org.bukkit.Bukkit; import sh.okx.rankup.RankupPlugin; @@ -13,6 +14,7 @@ public class Placeholders { private final DecimalFormat percentFormat; @Getter private final DecimalFormat simpleFormat; + private final List shortened; @Getter private RankupExpansion expansion; @@ -20,11 +22,28 @@ public class Placeholders { public Placeholders(RankupPlugin plugin) { this.plugin = plugin; + this.shortened = plugin.getConfig().getStringList("shorten"); this.moneyFormat = new DecimalFormat(plugin.getConfig().getString("placeholders.money-format")); this.percentFormat = new DecimalFormat(plugin.getConfig().getString("placeholders.percent-format")); this.simpleFormat = new DecimalFormat(plugin.getConfig().getString("placeholders.simple-format")); } + public String formatMoney(double money) { + String suffix = ""; + + for (int i = shortened.size(); i > 0; i--) { + double value = Math.pow(10, 3 * i); + if (money >= value) { + money /= value; + suffix = shortened.get(i - 1); + break; + } + } + + return moneyFormat.format(money) + suffix; + } + + public void register() { expansion = new RankupExpansion(plugin, this); if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { diff --git a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java index 40d1268..d2cfd03 100644 --- a/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java +++ b/src/main/java/sh/okx/rankup/placeholders/RankupExpansion.java @@ -55,7 +55,7 @@ public class RankupExpansion implements Expansion { if (parts.length > 3 && parts[3].equalsIgnoreCase("left")) { amount = amount - plugin.getEconomy().getBalance(player); } - return plugin.formatMoney(Math.max(0, amount)); + return plugin.getPlaceholders().formatMoney(Math.max(0, amount)); } else if (params.startsWith("status_")) { String[] parts = params.split("_", 2); Rank statusRank = rankups.getRankByName(parts[1]); @@ -116,7 +116,7 @@ public class RankupExpansion implements Expansion { return String.valueOf(simplify(orElse(prestige, r -> r.isIn(player) ? r.getRequirement(player, "money").getValueDouble() : 0, 0))); case "prestige_money_formatted": requirePrestiging(prestiges, params); - return plugin.formatMoney(orElse(prestige, r -> r.isIn(player) ? r.getRequirement(player, "money").getValueDouble() : 0, 0D)); + return plugin.getPlaceholders().formatMoney(orElse(prestige, r -> r.isIn(player) ? r.getRequirement(player, "money").getValueDouble() : 0, 0D)); case "current_rank": return orElse(rank, Rank::getRank, getPlaceholder("not-in-ladder")); case "current_rank_name": @@ -136,11 +136,11 @@ public class RankupExpansion implements Expansion { case "money": return String.valueOf(getMoney(player, rank)); case "money_formatted": - return plugin.formatMoney(getMoney(player, rank).doubleValue()); + return placeholders.formatMoney(getMoney(player, rank).doubleValue()); case "money_left": return String.valueOf(Math.max(0, orElse(rank, r -> simplify(r.getRequirement(player, "money").getValueDouble() - plugin.getEconomy().getBalance(player)), 0).doubleValue())); case "money_left_formatted": - return plugin.formatMoney(Math.max(0D, orElse(rank, r -> r.getRequirement(player, "money").getValueDouble() - plugin.getEconomy().getBalance(player), 0D))); + return placeholders.formatMoney(Math.max(0D, orElse(rank, r -> r.getRequirement(player, "money").getValueDouble() - plugin.getEconomy().getBalance(player), 0D))); case "percent_left": return String.valueOf(Math.max(0D, orElse(rank, r -> (1 - (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble())) * 100, 0).doubleValue())); case "percent_left_formatted": diff --git a/src/main/java/sh/okx/rankup/prestige/Prestiges.java b/src/main/java/sh/okx/rankup/prestige/Prestiges.java index 8514cff..1880da8 100644 --- a/src/main/java/sh/okx/rankup/prestige/Prestiges.java +++ b/src/main/java/sh/okx/rankup/prestige/Prestiges.java @@ -1,13 +1,26 @@ package sh.okx.rankup.prestige; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; +import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.ranks.RankElement; import sh.okx.rankup.ranks.RankList; -import sh.okx.rankup.RankupPlugin; public class Prestiges extends RankList { public Prestiges(RankupPlugin plugin, FileConfiguration config) { - super(plugin, config, section -> Prestige.deserialize(plugin, section)); + super(plugin, convert(plugin, config)); + } + + private static List convert(RankupPlugin plugin, FileConfiguration config) { + Map values = config.getValues(false); + List prestiges = new ArrayList<>(values.size()); + for (Map.Entry entry : values.entrySet()) { + prestiges.add(Prestige.deserialize(plugin, (ConfigurationSection) entry.getValue())); + } + return prestiges; } @Override diff --git a/src/main/java/sh/okx/rankup/ranks/RankList.java b/src/main/java/sh/okx/rankup/ranks/RankList.java index cf85f90..24d6341 100644 --- a/src/main/java/sh/okx/rankup/ranks/RankList.java +++ b/src/main/java/sh/okx/rankup/ranks/RankList.java @@ -1,14 +1,11 @@ package sh.okx.rankup.ranks; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.function.Function; import lombok.Getter; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import sh.okx.rankup.RankupPlugin; @@ -16,25 +13,17 @@ public abstract class RankList { protected RankupPlugin plugin; @Getter - protected FileConfiguration config; - @Getter private RankTree tree; - public RankList(RankupPlugin plugin, FileConfiguration config, - Function deserializer) { + public RankList(RankupPlugin plugin, Collection ranks) { this.plugin = plugin; - this.config = config; List> rankElements = new ArrayList<>(); - for (Map.Entry entry : config.getValues(false).entrySet()) { - ConfigurationSection rankSection = (ConfigurationSection) entry.getValue(); - if (validateSection(rankSection)) { - T apply = deserializer.apply(rankSection); - if (apply != null) { - // find next - rankElements.add(findNext(apply, rankElements)); - } + for (T rank : ranks) { + if (rank != null && validateSection(rank)) { + // find next + rankElements.add(findNext(rank, rankElements)); } else { - plugin.getLogger().warning("Ignoring rank: " + entry.getKey()); + plugin.getLogger().warning("Ignoring rank: " + rank); } } @@ -72,15 +61,15 @@ public abstract class RankList { return currentElement; } - protected boolean validateSection(ConfigurationSection section) { - String name = "'" + section.getName() + "'"; - String nextField = section.getString("next"); + protected boolean validateSection(T rank) { + String name = rank.getRank() == null ? "rank" : rank.getRank(); + String nextField = rank.getNext(); if (nextField == null || nextField.isEmpty()) { plugin.getLogger().warning("Rankup section " + name + " does not have a 'next' field."); plugin.getLogger().warning("Having a final rank (for example: \"Z: rank: 'Z'\") from 3.4.2 or earlier should no longer be used."); plugin.getLogger().warning("If this is intended as a final rank, you should delete " + name); return false; - } else if (!section.contains("requirements")) { + } else if (rank.getRequirements() == null) { plugin.getLogger().warning("Rank " + name + " does not have any requirements."); return false; } diff --git a/src/main/java/sh/okx/rankup/ranks/Rankup.java b/src/main/java/sh/okx/rankup/ranks/Rankup.java index 1709e12..8a29f45 100644 --- a/src/main/java/sh/okx/rankup/ranks/Rankup.java +++ b/src/main/java/sh/okx/rankup/ranks/Rankup.java @@ -1,32 +1,30 @@ package sh.okx.rankup.ranks; +import java.util.Objects; import org.bukkit.configuration.ConfigurationSection; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.ranks.requirements.RankRequirements; import sh.okx.rankup.ranks.requirements.RankRequirementsFactory; import java.util.List; +import sh.okx.rankup.serialization.RankSerialized; public class Rankup extends Rank { - public static Rankup deserialize(RankupPlugin plugin, ConfigurationSection section) { - String next = section.getString("next"); - String rank = section.getString("rank"); - String displayName = section.getString("display-name"); - - if (next == null || next.isEmpty()) { + public static Rankup deserialize(RankupPlugin plugin, RankSerialized serialized) { + if (serialized.getNext() == null || serialized.getNext().isEmpty()) { plugin.getLogger().warning("Having a final rank (for example: \"Z: rank: 'Z'\") from 3.4.2 or earlier should no longer be used."); - plugin.getLogger().warning("It is safe to just delete the final rank " + section.getName() + ""); - plugin.getLogger().warning("Rankup section '" + section.getName() + "' has a blank 'next' field, will be ignored."); + plugin.getLogger().warning("It is safe to just delete the final rank " + serialized.getRank() + ""); + plugin.getLogger().warning("Rankup section '" + serialized.getRank() + "' has a blank 'next' field, will be ignored."); return null; } - return new Rankup(section, + return new Rankup(serialized.getMessagesAsSection(), plugin, - next, - rank, - displayName, - RankRequirementsFactory.getRequirements(plugin, section), - section.getStringList("commands")); + serialized.getNext(), + serialized.getRank(), + serialized.getDisplayName(), + RankRequirementsFactory.getRequirements(plugin, serialized.getRequirements(), serialized.getPrestigeRequirements()), + Objects.requireNonNull(serialized.getCommands(), "rank commands are null")); } protected Rankup(ConfigurationSection section, RankupPlugin plugin, String next, String rank, String displayName, diff --git a/src/main/java/sh/okx/rankup/ranks/Rankups.java b/src/main/java/sh/okx/rankup/ranks/Rankups.java index ebb2c45..958c42a 100644 --- a/src/main/java/sh/okx/rankup/ranks/Rankups.java +++ b/src/main/java/sh/okx/rankup/ranks/Rankups.java @@ -1,12 +1,22 @@ package sh.okx.rankup.ranks; -import org.bukkit.configuration.file.FileConfiguration; +import java.util.ArrayList; +import java.util.List; import sh.okx.rankup.RankupPlugin; +import sh.okx.rankup.serialization.RankSerialized; public class Rankups extends RankList { - public Rankups(RankupPlugin plugin, FileConfiguration config) { - super(plugin, config, section -> Rankup.deserialize(plugin, section)); + public Rankups(RankupPlugin plugin, List serializedRanks) { + super(plugin, convert(plugin, serializedRanks)); + } + + private static List convert(RankupPlugin plugin, List ranks) { + List rankups = new ArrayList<>(ranks.size()); + for (RankSerialized rank : ranks) { + rankups.add(Rankup.deserialize(plugin, rank)); + } + return rankups; } @Override diff --git a/src/main/java/sh/okx/rankup/ranks/requirements/RankRequirementsFactory.java b/src/main/java/sh/okx/rankup/ranks/requirements/RankRequirementsFactory.java index 95f8692..3cb5a8b 100644 --- a/src/main/java/sh/okx/rankup/ranks/requirements/RankRequirementsFactory.java +++ b/src/main/java/sh/okx/rankup/ranks/requirements/RankRequirementsFactory.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.requirements.Requirement; @@ -20,6 +21,22 @@ public class RankRequirementsFactory { } } + public static RankRequirements getRequirements(RankupPlugin plugin, List requirements, + Map> prestigeRequirements) { + if (prestigeRequirements != null) { + ConfigurationSection section = new MemoryConfiguration(); + for (Map.Entry> entry : prestigeRequirements.entrySet()) { + section.set(entry.getKey(), entry.getValue()); + } + return getPrestigeListRequirements(plugin, section); + } else if (requirements != null) { + return getListRequirements(plugin, requirements); + } else { +// throw new IllegalArgumentException("No requirements set."); + return null; + } + } + private static Collection getRequirementStrings(ConfigurationSection section, String key) { if (section.isList(key)) { return section.getStringList(key); diff --git a/src/main/java/sh/okx/rankup/serialization/PrestigeSerialized.java b/src/main/java/sh/okx/rankup/serialization/PrestigeSerialized.java new file mode 100644 index 0000000..df219d2 --- /dev/null +++ b/src/main/java/sh/okx/rankup/serialization/PrestigeSerialized.java @@ -0,0 +1,25 @@ +package sh.okx.rankup.serialization; + +import java.util.List; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class PrestigeSerialized extends RankSerialized { + + private final String from; + private final String to; + + public PrestigeSerialized(String rank, String next, String displayName, + List commands, List requirements, + Map> prestigeRequirements, + Map messages, String from, String to) { + super(rank, next, displayName, commands, requirements, prestigeRequirements, messages); + this.from = from; + this.to = to; + } +} diff --git a/src/main/java/sh/okx/rankup/serialization/RankSerialized.java b/src/main/java/sh/okx/rankup/serialization/RankSerialized.java new file mode 100644 index 0000000..c4bdb5b --- /dev/null +++ b/src/main/java/sh/okx/rankup/serialization/RankSerialized.java @@ -0,0 +1,31 @@ +package sh.okx.rankup.serialization; + +import java.util.List; +import java.util.Map; +import lombok.Data; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; + +@Data +public class RankSerialized { + + private final String rank; + private final String next; + + private final String displayName; + + private final List commands; + + private final List requirements; + private final Map> prestigeRequirements; + + private final Map messages; + + public ConfigurationSection getMessagesAsSection() { + ConfigurationSection section = new MemoryConfiguration(); + for (Map.Entry entry : messages.entrySet()) { + section.set(entry.getKey(), entry.getValue()); + } + return section; + } +} diff --git a/src/main/java/sh/okx/rankup/serialization/ShadowDeserializer.java b/src/main/java/sh/okx/rankup/serialization/ShadowDeserializer.java new file mode 100644 index 0000000..b75bcbb --- /dev/null +++ b/src/main/java/sh/okx/rankup/serialization/ShadowDeserializer.java @@ -0,0 +1,67 @@ +package sh.okx.rankup.serialization; + +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import com.electronwill.nightconfig.core.UnmodifiableConfig.Entry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ShadowDeserializer { + + public static List deserialize(UnmodifiableConfig ranks) { + List ranksList = new ArrayList<>(ranks.size()); + for (Entry entry : ranks.entrySet()) { + UnmodifiableConfig value = entry.getValue(); + if (value == null) continue; + String rank = value.get("rank"); + String next = value.get("next"); + String displayName = value.get("display-name"); + List commands = value.getOrElse("commands", Collections.emptyList()); + List requirements; + Map> prestigeRequirements; + Object requirementsObject = value.get("requirements"); + if (requirementsObject instanceof UnmodifiableConfig) { + requirements = null; + UnmodifiableConfig requirementsConfig = (UnmodifiableConfig) requirementsObject; + prestigeRequirements = new HashMap<>(requirementsConfig.size()); + for (Entry requirementEntry : requirementsConfig.entrySet()) { + prestigeRequirements.put(requirementEntry.getKey(), requirementEntry.getValue()); + } + } else { + prestigeRequirements = null; + if (requirementsObject instanceof String) { + requirements = Collections.singletonList((String) requirementsObject); + } else if (requirementsObject instanceof List) { + requirements = (List) requirementsObject; + } else { + requirements = Collections.emptyList(); + } + } + + UnmodifiableConfig messagesConfig = value.get("rankup"); + Map messages; + if (messagesConfig != null) { + messages = new HashMap<>(); + updateMap(messages, messagesConfig, "rankup."); + } else { + messages = Collections.emptyMap(); + } + + ranksList.add(new RankSerialized(rank, next, displayName, commands, requirements, prestigeRequirements, messages)); + } + return ranksList; + } + + private static void updateMap(Map map, UnmodifiableConfig config, String prefix) { + for (Entry message : config.entrySet()) { + Object value = message.getValue(); + if (value instanceof String) { + map.put(prefix + message.getKey(), (String) value); + } else if (value instanceof UnmodifiableConfig) { + updateMap(map, (UnmodifiableConfig) value, prefix + message.getKey() + "."); + } + } + } +} diff --git a/src/main/java/sh/okx/rankup/serialization/YamlDeserializer.java b/src/main/java/sh/okx/rankup/serialization/YamlDeserializer.java new file mode 100644 index 0000000..202e3e8 --- /dev/null +++ b/src/main/java/sh/okx/rankup/serialization/YamlDeserializer.java @@ -0,0 +1,57 @@ +package sh.okx.rankup.serialization; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemorySection; + +public class YamlDeserializer { + + public static List deserialize(ConfigurationSection ranks) { + Set rankKeys = ranks.getKeys(false); + List ranksList = new ArrayList<>(rankKeys.size()); + for (String rankKey : rankKeys) { + ConfigurationSection section = ranks.getConfigurationSection(rankKey); + if (section == null) continue; + String rank = section.getString("rank"); + String next = section.getString("next"); + String displayName = section.getString("display-name"); + List commands = section.getStringList("commands"); + List requirements; + Map> prestigeRequirements; + if (section.isConfigurationSection("requirements")) { + requirements = null; + Set keys = section.getKeys(false); + prestigeRequirements = new HashMap<>(keys.size()); + ConfigurationSection requirementsSection = section.getConfigurationSection("requirements"); + for (String key : keys) { + prestigeRequirements.put(key, requirementsSection.getStringList(key)); + } + } else { + prestigeRequirements = null; + requirements = section.getStringList("requirements"); + } + + ConfigurationSection rankupSection = section.getConfigurationSection("rankup"); + Map messages; + if (rankupSection != null) { + + Set rankup = rankupSection.getKeys(true); + messages = new HashMap<>(rankup.size()); + for (String key : rankup) { + messages.put(MemorySection.createPath(rankupSection, key, section), rankupSection.getString(key)); + } + } else { + messages = Collections.emptyMap(); + } + + ranksList.add(new RankSerialized(rank, next, displayName, commands, requirements, prestigeRequirements, messages)); + } + return ranksList; + } + +} diff --git a/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java b/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java index 709ea6d..8881ac2 100644 --- a/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java +++ b/src/main/java/sh/okx/rankup/text/LegacyTextProcessor.java @@ -3,14 +3,14 @@ package sh.okx.rankup.text; import java.util.Map; import java.util.function.Function; import sh.okx.rankup.messages.pebble.RankContext; -import sh.okx.rankup.text.pebble.PebbleOptions; +import sh.okx.rankup.placeholders.Placeholders; public class LegacyTextProcessor implements TextProcessor { private final Map pebbleContext; - private final PebbleOptions options; + private final Placeholders options; - public LegacyTextProcessor(Map pebbleContext, PebbleOptions options) { + public LegacyTextProcessor(Map pebbleContext, Placeholders options) { this.pebbleContext = pebbleContext; this.options = options; } diff --git a/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java b/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java index 88a9c69..1baa96d 100644 --- a/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java +++ b/src/main/java/sh/okx/rankup/text/TextProcessorBuilder.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Map; import org.bukkit.entity.Player; import org.jetbrains.annotations.Nullable; -import sh.okx.rankup.text.pebble.PebbleOptions; +import sh.okx.rankup.placeholders.Placeholders; import sh.okx.rankup.text.pebble.PebbleTextProcessor; public class TextProcessorBuilder { @@ -17,7 +17,7 @@ public class TextProcessorBuilder { return this; } - public TextProcessorBuilder pebble(Map context, PebbleOptions options) { + public TextProcessorBuilder pebble(Map context, Placeholders options) { processors.add(new PebbleTextProcessor(context, options)); return this; } @@ -27,7 +27,7 @@ public class TextProcessorBuilder { return this; } - public TextProcessorBuilder legacy(Map context, PebbleOptions options) { + public TextProcessorBuilder legacy(Map context, Placeholders options) { processors.add(new LegacyTextProcessor(context, options)); return this; } diff --git a/src/main/java/sh/okx/rankup/text/pebble/MoneyShortFilter.java b/src/main/java/sh/okx/rankup/text/pebble/MoneyShortFilter.java new file mode 100644 index 0000000..804e29d --- /dev/null +++ b/src/main/java/sh/okx/rankup/text/pebble/MoneyShortFilter.java @@ -0,0 +1,38 @@ +package sh.okx.rankup.text.pebble; + +import com.mitchellbosecke.pebble.error.PebbleException; +import com.mitchellbosecke.pebble.extension.Filter; +import com.mitchellbosecke.pebble.template.EvaluationContext; +import com.mitchellbosecke.pebble.template.PebbleTemplate; +import java.util.List; +import java.util.Map; +import sh.okx.rankup.placeholders.Placeholders; + +public class MoneyShortFilter implements Filter { + + private final Placeholders placeholders; + + public MoneyShortFilter(Placeholders placeholders) { + this.placeholders = placeholders; + } + + @Override + public List getArgumentNames() { + return null; + } + + @Override + public Object apply(Object input, Map args, PebbleTemplate self, + EvaluationContext context, int lineNumber) throws PebbleException { + if (input == null) { + return null; + } + if (!(input instanceof Number)) { + throw new PebbleException(null, "The input for the 'MoneyShortFilter' filter has to be a number: " + input, + lineNumber, self.getName()); + } + + Number number = (Number) input; + return placeholders.formatMoney(number.doubleValue()); + } +} diff --git a/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java b/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java deleted file mode 100644 index 4490ca7..0000000 --- a/src/main/java/sh/okx/rankup/text/pebble/PebbleOptions.java +++ /dev/null @@ -1,11 +0,0 @@ -package sh.okx.rankup.text.pebble; - -import java.text.DecimalFormat; -import lombok.Data; - -@Data -public class PebbleOptions { - private final DecimalFormat moneyFormat; - private final DecimalFormat percentFormat; - private final DecimalFormat simpleFormat; -} diff --git a/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java b/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java index 85208b2..2a2878c 100644 --- a/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java +++ b/src/main/java/sh/okx/rankup/text/pebble/PebbleTextProcessor.java @@ -6,17 +6,23 @@ import com.mitchellbosecke.pebble.extension.Filter; import com.mitchellbosecke.pebble.loader.StringLoader; import java.io.IOException; import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; +import java.util.logging.Logger; +import org.bukkit.plugin.java.JavaPlugin; +import sh.okx.rankup.RankupPlugin; +import sh.okx.rankup.messages.pebble.InvalidRequirementException; +import sh.okx.rankup.placeholders.Placeholders; import sh.okx.rankup.text.TextProcessor; public class PebbleTextProcessor implements TextProcessor { private final Map context; - private final PebbleOptions options; + private final Placeholders options; - public PebbleTextProcessor(Map context, PebbleOptions options) { + public PebbleTextProcessor(Map context, Placeholders options) { this.context = context; this.options = options; } @@ -30,7 +36,10 @@ public class PebbleTextProcessor implements TextProcessor { Map filters = new HashMap<>(); if (options != null) { DecimalFormat moneyFormat = options.getMoneyFormat(); - if (moneyFormat != null) filters.put("money", new DecimalFormatFilter(moneyFormat)); + if (moneyFormat != null) { + filters.put("money", new DecimalFormatFilter(moneyFormat)); + filters.put("shortmoney", new MoneyShortFilter(options)); + } DecimalFormat percentFormat = options.getPercentFormat(); if (percentFormat != null) filters.put("percent", new DecimalFormatFilter(percentFormat)); @@ -44,8 +53,27 @@ public class PebbleTextProcessor implements TextProcessor { .loader(new StringLoader()).build(); StringWriter writer = new StringWriter(); try { - engine.getTemplate(string).evaluate(writer, context); - return writer.toString(); + try { + engine.getTemplate(string).evaluate(writer, context); + return writer.toString(); + } catch (RuntimeException ex) { + if (ex.getCause() instanceof InvocationTargetException) { + if (ex.getCause().getCause() instanceof InvalidRequirementException) { + InvalidRequirementException cause = (InvalidRequirementException) ex.getCause().getCause(); + Logger logger = JavaPlugin.getPlugin(RankupPlugin.class).getLogger(); + logger.severe("Unknown requirement \"" + cause.getRequirement() + "\" on rank \"" + cause.getRank().getRank() + "\" in message:"); + for (String line : string.split("\n")) { + logger.severe(line); + } + logger.severe("Change the message to not use that requirement, or add the requirement to the rank in the config."); + } else { + ex.printStackTrace(); + } + } else { + ex.printStackTrace(); + } + return "Unable to parse message, please check console"; + } } catch (IOException e) { e.printStackTrace(); return string; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1937823..c708d11 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -100,6 +100,7 @@ placeholders: # set to an empty list to disable # 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. +# this is used in the "| shortmoney" filter shorten: - 'K' - 'M' diff --git a/src/main/resources/locale/en.yml b/src/main/resources/locale/en.yml index 2474396..b7b781b 100644 --- a/src/main/resources/locale/en.yml +++ b/src/main/resources/locale/en.yml @@ -1,6 +1,6 @@ # the messages in this section can be customised for each rankup in rankups.yml. rankup: - requirements-not-met: "&cYou need {{rank.requirement('money').total | simple}} money to rankup." + requirements-not-met: "&cYou need {{rank.requirement('money').total | money}} money to rankup." no-rankup: "&eYou are at the highest rank." # set to an empty string, ie: success-public: "" # to hide that message. @@ -77,7 +77,7 @@ rankup: plural: "&cYou must wait {{seconds_left}} more seconds to rankup again." # prestige messages can also be customised prestige: - requirements-not-met: "&cYou need {{rank.requirement('money').total | simple}} money to prestige." + requirements-not-met: "&cYou need {{rank.requirement('money').total | money}} money to prestige." no-prestige: "&eYou are at the highest prestige." success-public: "&a{{player}} &ehas prestiged to: &d{{next.rank}}" @@ -116,5 +116,4 @@ prestige: plural: "&cYou must wait {{seconds_left}} more seconds to prestige again." not-high-enough: "&cYou cannot prestige at your rank!" -not-in-ladder: "&cSorry, but we could not find any rankups for the group(s) you are in. Use /ranks to list the rankups." -invalid-rankup: "&cInvalid rankup defined in config, please check console." \ No newline at end of file +not-in-ladder: "&cSorry, but we could not find any rankups for the group(s) you are in. Use /ranks to list the rankups." \ No newline at end of file diff --git a/src/main/resources/locale/es.yml b/src/main/resources/locale/es.yml index 1894d50..0ab1afd 100644 --- a/src/main/resources/locale/es.yml +++ b/src/main/resources/locale/es.yml @@ -1,4 +1,4 @@ -# the messages in this section can be customised for each rankup in rankups.yml. + money# the messages in this section can be customised for each rankup in rankups.yml. rankup: requirements-not-met: "&cNo satisfaces los requisitos para seguir al siguiente rango." no-rankup: "&eEstás en el último rango." @@ -116,4 +116,3 @@ prestige: not-high-enough: "&c¡No puedes prestigiar a tu rango!" not-in-ladder: "&cPerdón, pero no hemos podido encontrar rangos en los grupos que perteneces. Usa /ranks para ver los rangos." -invalid-rankup: "&cRango inválido definido en la configuración, verifica que todo esté correcto y revisa la consola." diff --git a/src/main/resources/locale/fr.yml b/src/main/resources/locale/fr.yml index 859f0ec..2dd312a 100644 --- a/src/main/resources/locale/fr.yml +++ b/src/main/resources/locale/fr.yml @@ -100,5 +100,4 @@ prestige: plural: "&cVous devez attendre encore {{seconds_left}} secondes pour de nouveau passer un rang." not-high-enough: "&cVous ne pouvez pas passer de prestige à votre rang !" -not-in-ladder: "&cDésolé, mais nous n'avons pas trouvé de rang pour le(s) groupe(s) dans lequel(s) vous êtes. Tapez /ranks pour voir la liste des rangs." -invalid-rankup: "La configuration de Rankup est invalide, veuillez vérifier la console." \ No newline at end of file +not-in-ladder: "&cDésolé, mais nous n'avons pas trouvé de rang pour le(s) groupe(s) dans lequel(s) vous êtes. Tapez /ranks pour voir la liste des rangs." \ No newline at end of file diff --git a/src/main/resources/locale/it.yml b/src/main/resources/locale/it.yml index c78ec67..1a47d1d 100644 --- a/src/main/resources/locale/it.yml +++ b/src/main/resources/locale/it.yml @@ -113,4 +113,3 @@ prestige: not-high-enough: "&cNon puoi effettuare un prestige al tuo rank!" not-in-ladder: "&cNon riusciamo a trovare nessun avanzamento di rank per il tuo gruppo. Scrivi /ranks per ottenere una lista degli avanzamenti disponibili." -invalid-rankup: "&cRankup invalido definito nel file di configurazione, controlla la console." diff --git a/src/main/resources/locale/nl.yml b/src/main/resources/locale/nl.yml index f922899..a31149b 100644 --- a/src/main/resources/locale/nl.yml +++ b/src/main/resources/locale/nl.yml @@ -115,5 +115,4 @@ prestige: plural: "&cJe moet {{seconds_left}} secondes wachten om weer te prestigen." not-high-enough: "&cJe kan niet prestigen in jouw rang!" -not-in-ladder: "&cSorry, maar we konden geen rangen vinden voor de group(en) waar jij in zit. Gebruik /ranks om de lijst van rangen te weergeven." -invalid-rankup: "&cOngeldige rang gedefinieerd in de configuratie, check AUB het bedieningspaneel." \ No newline at end of file +not-in-ladder: "&cSorry, maar we konden geen rangen vinden voor de group(en) waar jij in zit. Gebruik /ranks om de lijst van rangen te weergeven." \ No newline at end of file diff --git a/src/main/resources/locale/pt_br.yml b/src/main/resources/locale/pt_br.yml index 8899c5e..a45ee07 100644 --- a/src/main/resources/locale/pt_br.yml +++ b/src/main/resources/locale/pt_br.yml @@ -103,5 +103,4 @@ prestige: plural: "&cVocê deve esperar {{seconds_left}} segundos para subir de prestígio novamente." not-high-enough: "&cVocê não pode subir de prestígio nesse rank!" -not-in-ladder: "&cDesculpa, não conseguimos achar nenhum rank para você subir." -invalid-rankup: "Rankup inválido definido na config, por favor confira o console." \ No newline at end of file +not-in-ladder: "&cDesculpa, não conseguimos achar nenhum rank para você subir." \ No newline at end of file diff --git a/src/main/resources/locale/ru.yml b/src/main/resources/locale/ru.yml index d980d16..b6197de 100644 --- a/src/main/resources/locale/ru.yml +++ b/src/main/resources/locale/ru.yml @@ -101,4 +101,3 @@ prestige: not-high-enough: "&cВы не можете поднять уровень престижа в этом ранге" not-in-ladder: "&cПростите, но мне не можем найти какие-нибудь повышения для Вашей группы." -invalid-rankup: "В конфигурации определён неверное повышение, пожалуйста, проверьте консоль." diff --git a/src/main/resources/locale/zh_cn.yml b/src/main/resources/locale/zh_cn.yml index 4947183..180ea5a 100644 --- a/src/main/resources/locale/zh_cn.yml +++ b/src/main/resources/locale/zh_cn.yml @@ -118,4 +118,3 @@ prestige: not-high-enough: "&c您无法在您当前等级上进行声望晋升!" not-in-ladder: "&c抱歉,我们找不到您所在小组的任何段位等级。使用 /ranks 列出所有段位等级。" -invalid-rankup: "&c配置中定义了无效的 段位晋升,请检查控制台获取更多信息。" diff --git a/src/main/resources/rankups.yml b/src/main/resources/rankups.yml index 567c59f..1eb94fb 100644 --- a/src/main/resources/rankups.yml +++ b/src/main/resources/rankups.yml @@ -1,7 +1,7 @@ # # If you are adding your own ranks, make sure to delete the example ranks! # Need help setting the plugin up? -# Read an example: https://github.com/okx-code/Rankup3/wiki/Configuration-Example +# Read the wiki: https://okx.sh/rankup/Home.html # Join the discord server for live support: https://discord.gg/maB4382 (buyers only) # @@ -14,7 +14,7 @@ Aexample: next: 'B' # List of requirements to go to the next rank # This example will charge 1000 money to rankup from A to B. - # https://github.com/okx-code/Rankup3/wiki/List-of-Requirements + # https://okx.sh/rankup/List-of-Requirements.html # custom requirements can also be added by other plugins. requirements: - 'money 1000' diff --git a/src/test/java/sh/okx/rankup/RankupCommandsTest.java b/src/test/java/sh/okx/rankup/RankupCommandsTest.java new file mode 100644 index 0000000..db09752 --- /dev/null +++ b/src/test/java/sh/okx/rankup/RankupCommandsTest.java @@ -0,0 +1,5 @@ +package sh.okx.rankup; + +public class RankupCommandsTest extends RankupTest { + +} diff --git a/src/test/java/sh/okx/rankup/RankupCommandTest.java b/src/test/java/sh/okx/rankup/commands/CommandInfoTest.java similarity index 90% rename from src/test/java/sh/okx/rankup/RankupCommandTest.java rename to src/test/java/sh/okx/rankup/commands/CommandInfoTest.java index f9ef5c1..ce82a37 100644 --- a/src/test/java/sh/okx/rankup/RankupCommandTest.java +++ b/src/test/java/sh/okx/rankup/commands/CommandInfoTest.java @@ -1,4 +1,4 @@ -package sh.okx.rankup; +package sh.okx.rankup.commands; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -6,8 +6,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import be.seeseemelk.mockbukkit.entity.PlayerMock; import org.junit.jupiter.api.Test; +import sh.okx.rankup.RankupTest; -public class RankupCommandTest extends RankupTest { +public class CommandInfoTest extends RankupTest { @Test public void testPlaceholders() { // placeholders command should never throw an exception diff --git a/src/test/java/sh/okx/rankup/prestige/BrokenPrestigeTest.java b/src/test/java/sh/okx/rankup/prestige/BrokenPrestigeTest.java new file mode 100644 index 0000000..ae5227e --- /dev/null +++ b/src/test/java/sh/okx/rankup/prestige/BrokenPrestigeTest.java @@ -0,0 +1,25 @@ +package sh.okx.rankup.prestige; + +import static org.junit.jupiter.api.Assertions.*; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import org.bukkit.ChatColor; +import org.junit.jupiter.api.Test; +import sh.okx.rankup.RankupTest; + +public class BrokenPrestigeTest extends RankupTest { + + public BrokenPrestigeTest() { + super("brokenprestige"); + } + + @Test + public void testPrestige() { + PlayerMock player = server.addPlayer(); + plugin.getPermissions().addGroup(player.getUniqueId(), "C"); + + assertNull(plugin.getPrestiges().getByPlayer(player)); + plugin.getHelper().rankup(player); + player.assertSaid(ChatColor.YELLOW + "You are at the highest rank."); + } +} diff --git a/src/test/java/sh/okx/rankup/providers/TestEconomy.java b/src/test/java/sh/okx/rankup/providers/TestEconomy.java index a096984..a011382 100644 --- a/src/test/java/sh/okx/rankup/providers/TestEconomy.java +++ b/src/test/java/sh/okx/rankup/providers/TestEconomy.java @@ -12,7 +12,7 @@ public class TestEconomy implements Economy { @Override public double getBalance(Player player) { - return balances.get(player.getUniqueId()); + return balances.getOrDefault(player.getUniqueId(), 0D); } @Override diff --git a/src/test/java/sh/okx/rankup/toml/TomlTest.java b/src/test/java/sh/okx/rankup/toml/TomlTest.java new file mode 100644 index 0000000..e769a04 --- /dev/null +++ b/src/test/java/sh/okx/rankup/toml/TomlTest.java @@ -0,0 +1,55 @@ +package sh.okx.rankup.toml; + +import static org.junit.jupiter.api.Assertions.*; + +import be.seeseemelk.mockbukkit.entity.PlayerMock; +import org.bukkit.ChatColor; +import org.junit.jupiter.api.Test; +import sh.okx.rankup.RankupTest; +import sh.okx.rankup.ranks.Rankups; + +public class TomlTest extends RankupTest { + + public TomlTest() { + super("toml"); + } + + @Test + public void testRequirementsNotMet() { + PlayerMock player = server.addPlayer(); + + Rankups ranks = plugin.getRankups(); + assertEquals(1500, ranks.getFirst().getRequirement(null, "money").getValueDouble()); + + plugin.getPermissions().addGroup(player.getUniqueId(), "C"); + player.addAttachment(plugin, "rankup.rankup", true); + plugin.getHelper().rankup(player); + + player.assertSaid("toml"); + } + + @Test + public void testRankup() { + PlayerMock player = server.addPlayer(); + plugin.getPermissions().addGroup(player.getUniqueId(), "B"); + plugin.getEconomy().setPlayer(player, 10000); + player.addAttachment(plugin, "rankup.rankup", true); + + plugin.getHelper().rankup(player); + + assertTrue(plugin.getPermissions().inGroup(player.getUniqueId(), "C")); + } + + @Test + public void testRanks() { + PlayerMock player = server.addPlayer(); + plugin.getPermissions().addGroup(player.getUniqueId(), "C"); + + player.addAttachment(plugin, "rankup.ranks", true); + plugin.getCommand("ranks").execute(player, "ranks", new String[0]); + player.assertSaid(ChatColor.GRAY + "A " + ChatColor.DARK_GRAY + "\u00bb " + ChatColor.GRAY + "B"); + player.assertSaid(ChatColor.GRAY + "B " + ChatColor.DARK_GRAY + "\u00bb " + ChatColor.GRAY + "C"); + player.assertSaid(ChatColor.RED + "C " + ChatColor.YELLOW + "\u00bb " + ChatColor.RED + "D o"); + player.assertNoMoreSaid(); + } +} diff --git a/src/test/resources/brokenprestige/config.yml b/src/test/resources/brokenprestige/config.yml new file mode 100644 index 0000000..b3907bc --- /dev/null +++ b/src/test/resources/brokenprestige/config.yml @@ -0,0 +1,36 @@ +version: 10 +locale: en +autorankup-interval: 0 +ranks: true +prestiges: true +ranks-gui: false +prestige: true # enable prestige +notify-update: true +permission-rankup: false +confirmation-type: 'gui' +cooldown: 1 +max-rankup: + enabled: false + individual-messages: true +text: + timeout: 10 +placeholders: + money-format: "#,##0.##" + percent-format: "0.##" + simple-format: "#.##" + not-in-ladder: "None" + no-prestige: "None" + highest-rank: "None" + status: + complete: "Complete" + current: "Current" + incomplete: "Incomplete" + last-rank-display-name: "last rank" +shorten: + - 'K' + - 'M' + - 'B' + - 'T' + - 'Q' + - 'Qu' + - 'S' diff --git a/src/test/resources/brokenprestige/rankups.yml b/src/test/resources/brokenprestige/rankups.yml new file mode 100644 index 0000000..4170025 --- /dev/null +++ b/src/test/resources/brokenprestige/rankups.yml @@ -0,0 +1,10 @@ +Arank: + rank: 'A' + next: 'B' + requirements: + - 'money 1000' +Brank: + rank: 'B' + next: 'C' + requirements: + - 'money 2500' \ No newline at end of file diff --git a/src/test/resources/toml/rankups.toml b/src/test/resources/toml/rankups.toml new file mode 100644 index 0000000..eb30668 --- /dev/null +++ b/src/test/resources/toml/rankups.toml @@ -0,0 +1,25 @@ +[A] +rank = "A" +next = "B" +requirements = [ + "money 1500" +] +[B] +rank = "B" +next = "C" +requirements = [ + "money 2500" +] +[C] +rank = "C" +next = "D" +requirements = [ + "money 6000", + "xp-level 2" +] +[C.rankup] + requirements-not-met = "toml" + [C.rankup.list] + complete = "&7{{rank.rank}} &8\u00bb &7{{next.rank}} t" + current = "&c{{rank.rank}} &e\u00bb &c{{next.rank}} o" + incomplete = "&r{{rank.rank}} &e\u00bb &r{{next.rank}} m" \ No newline at end of file