3.9-beta.2

This commit is contained in:
okx-code
2020-06-26 23:19:41 +01:00
parent dd81b2432b
commit 55e190a5c2
27 changed files with 617 additions and 272 deletions
+3 -1
View File
@@ -4,7 +4,7 @@ plugins {
} }
group 'sh.okx' group 'sh.okx'
version '3.9-beta.1' version '3.9-beta.2'
repositories { repositories {
mavenCentral() mavenCentral()
@@ -26,6 +26,8 @@ repositories {
dependencies { dependencies {
testImplementation group: 'junit', name: 'junit', version: '4.12' testImplementation group: 'junit', name: 'junit', version: '4.12'
testImplementation 'com.github.seeseemelk:MockBukkit-v1.15:0.3.0-SNAPSHOT'
compileOnly 'org.jetbrains:annotations:16.0.2' compileOnly 'org.jetbrains:annotations:16.0.2'
implementation 'org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT' implementation 'org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT'
implementation('com.github.Realizedd:TokenManager:3.2.4') { implementation('com.github.Realizedd:TokenManager:3.2.4') {
@@ -27,7 +27,7 @@ public class RankupHelper {
/** /**
* Players who cannot rankup/prestige for a certain amount of time. * Players who cannot rankup/prestige for a certain amount of time.
*/ */
private Map<Player, Long> cooldowns = new HashMap<>(); private final Map<Player, Long> cooldowns = new HashMap<>();
public RankupHelper(RankupPlugin plugin) { public RankupHelper(RankupPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
+45 -35
View File
@@ -1,7 +1,6 @@
package sh.okx.rankup; package sh.okx.rankup;
import lombok.Getter; import lombok.Getter;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -11,14 +10,19 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.InventoryView;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import sh.okx.rankup.commands.*; import sh.okx.rankup.commands.*;
import sh.okx.rankup.economy.Economy;
import sh.okx.rankup.economy.EconomyProvider;
import sh.okx.rankup.economy.VaultEconomyProvider;
import sh.okx.rankup.gui.Gui; import sh.okx.rankup.gui.Gui;
import sh.okx.rankup.gui.GuiListener; import sh.okx.rankup.gui.GuiListener;
import sh.okx.rankup.hook.GroupProvider; import sh.okx.rankup.hook.GroupProvider;
import sh.okx.rankup.hook.PermissionManager; import sh.okx.rankup.hook.PermissionManager;
import sh.okx.rankup.hook.VaultPermissionManager;
import sh.okx.rankup.messages.Message; import sh.okx.rankup.messages.Message;
import sh.okx.rankup.messages.MessageBuilder; import sh.okx.rankup.messages.MessageBuilder;
import sh.okx.rankup.messages.NullMessageBuilder; import sh.okx.rankup.messages.NullMessageBuilder;
@@ -31,7 +35,7 @@ import sh.okx.rankup.ranks.RankList;
import sh.okx.rankup.ranks.Rankups; import sh.okx.rankup.ranks.Rankups;
import sh.okx.rankup.requirements.Requirement; import sh.okx.rankup.requirements.Requirement;
import sh.okx.rankup.requirements.RequirementRegistry; import sh.okx.rankup.requirements.RequirementRegistry;
import sh.okx.rankup.requirements.XpLevelDeductibleRequirement; import sh.okx.rankup.requirements.requirement.XpLevelDeductibleRequirement;
import sh.okx.rankup.requirements.requirement.*; import sh.okx.rankup.requirements.requirement.*;
import sh.okx.rankup.requirements.requirement.advancedachievements.AdvancedAchievementsAchievementRequirement; import sh.okx.rankup.requirements.requirement.advancedachievements.AdvancedAchievementsAchievementRequirement;
import sh.okx.rankup.requirements.requirement.advancedachievements.AdvancedAchievementsTotalRequirement; import sh.okx.rankup.requirements.requirement.advancedachievements.AdvancedAchievementsTotalRequirement;
@@ -78,8 +82,20 @@ public class RankupPlugin extends JavaPlugin {
private Placeholders placeholders; private Placeholders placeholders;
@Getter @Getter
private RankupHelper helper; private RankupHelper helper;
private AutoRankup autoRankup; protected AutoRankup autoRankup = new AutoRankup(this);
private String errorMessage; private String errorMessage;
private PermissionManager permissionManager = new VaultPermissionManager(this);
private EconomyProvider economyProvider = new VaultEconomyProvider();
public RankupPlugin() {
super();
}
protected RankupPlugin(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file, PermissionManager permissionManager, EconomyProvider economyProvider) {
super(loader, description, dataFolder, file);
this.permissionManager = permissionManager;
this.economyProvider = economyProvider;
}
@Override @Override
public void onEnable() { public void onEnable() {
@@ -87,23 +103,25 @@ public class RankupPlugin extends JavaPlugin {
reload(true); reload(true);
Metrics metrics = new Metrics(this); if (System.getProperty("TEST") == null) {
metrics.addCustomChart(new Metrics.SimplePie("confirmation", Metrics metrics = new Metrics(this);
() -> config.getString("confirmation-type", "unknown"))); metrics.addCustomChart(new Metrics.SimplePie("confirmation",
metrics.addCustomChart(new Metrics.AdvancedPie("requirements", () -> { () -> config.getString("confirmation-type", "unknown")));
Map<String, Integer> map = new HashMap<>(); metrics.addCustomChart(new Metrics.AdvancedPie("requirements", () -> {
addAll(map, rankups); Map<String, Integer> map = new HashMap<>();
if (prestiges != null) { addAll(map, rankups);
addAll(map, prestiges); if (prestiges != null) {
} addAll(map, prestiges);
return map; }
})); return map;
metrics.addCustomChart(new Metrics.SimplePie("prestige", }));
() -> config.getBoolean("prestige") ? "enabled" : "disabled")); metrics.addCustomChart(new Metrics.SimplePie("prestige",
metrics.addCustomChart(new Metrics.SimplePie("permission-rankup", () -> config.getBoolean("prestige") ? "enabled" : "disabled"));
() -> config.getBoolean("permission-rankup") ? "enabled" : "disabled")); metrics.addCustomChart(new Metrics.SimplePie("permission-rankup",
metrics.addCustomChart(new Metrics.SimplePie("notify-update", () -> config.getBoolean("permission-rankup") ? "enabled" : "disabled"));
() -> config.getBoolean("notify-update") ? "enabled" : "disabled")); metrics.addCustomChart(new Metrics.SimplePie("notify-update",
() -> config.getBoolean("notify-update") ? "enabled" : "disabled"));
}
if (config.getBoolean("ranks")) { if (config.getBoolean("ranks")) {
getCommand("ranks").setExecutor(new RanksCommand(this)); getCommand("ranks").setExecutor(new RanksCommand(this));
@@ -142,8 +160,6 @@ public class RankupPlugin extends JavaPlugin {
config = loadConfig("config.yml"); config = loadConfig("config.yml");
PermissionManager permissionManager = new PermissionManager(this);
if (config.getBoolean("permission-rankup")) { if (config.getBoolean("permission-rankup")) {
permissions = permissionManager.permissionOnlyProvider(); permissions = permissionManager.permissionOnlyProvider();
} else { } else {
@@ -158,12 +174,11 @@ public class RankupPlugin extends JavaPlugin {
closeInventories(); closeInventories();
loadConfigs(init); loadConfigs(init);
if (autoRankup != null) {
autoRankup.cancel();
}
long time = (long) (config.getDouble("autorankup-interval") * 60 * 20); long time = (long) (config.getDouble("autorankup-interval") * 60 * 20);
if (time > 0) { if (time > 0) {
autoRankup = new AutoRankup(this); if (!autoRankup.isCancelled()) {
autoRankup.cancel();
}
autoRankup.runTaskTimer(this, time, time); autoRankup.runTaskTimer(this, time, time);
} }
@@ -239,7 +254,7 @@ public class RankupPlugin extends JavaPlugin {
messages = YamlConfiguration.loadConfiguration(localeFile); messages = YamlConfiguration.loadConfiguration(localeFile);
if (init) { if (init) {
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> { Bukkit.getScheduler().runTask(this, () -> {
refreshRanks(); refreshRanks();
error(); error();
}); });
@@ -302,6 +317,7 @@ public class RankupPlugin extends JavaPlugin {
new XpLevelRequirement(this, "xp-levelh"), new XpLevelRequirement(this, "xp-levelh"),
new XpLevelDeductibleRequirement(this, "xp-level"), new XpLevelDeductibleRequirement(this, "xp-level"),
new PlaytimeMinutesRequirement(this), new PlaytimeMinutesRequirement(this),
new AdvancementRequirement(this),
new GroupRequirement(this), new GroupRequirement(this),
new PermissionRequirement(this), new PermissionRequirement(this),
new PlaceholderRequirement(this), new PlaceholderRequirement(this),
@@ -353,13 +369,7 @@ public class RankupPlugin extends JavaPlugin {
} }
} }
private void setupEconomy() { private void setupEconomy() {
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager() economy = economyProvider.getEconomy();
.getRegistration(Economy.class);
if (rsp != null) {
economy = rsp.getProvider();
} else {
getLogger().warning("No economy found. The 'money' requirement will be disabled.");
}
} }
public String formatMoney(double money) { public String formatMoney(double money) {
@@ -158,7 +158,7 @@ public class InfoCommand implements TabExecutor {
if (args.length > 1 && args[1].equalsIgnoreCase("status")) { if (args.length > 1 && args[1].equalsIgnoreCase("status")) {
for (Rank rank : plugin.getRankups().getTree()) { for (Rank rank : plugin.getRankups().getTree()) {
String placeholder = "status_" + rank.getRank(); String placeholder = "status_" + rank.getRank();
sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().onPlaceholderRequest(sender instanceof Player ? (Player) sender : null, placeholder)); sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().placeholder(sender instanceof Player ? (Player) sender : null, placeholder));
} }
return true; return true;
} }
@@ -178,7 +178,7 @@ public class InfoCommand implements TabExecutor {
"next_rank", "next_rank",
}; };
for (String placeholder : placeholders) { for (String placeholder : placeholders) {
sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().onPlaceholderRequest(sender instanceof Player ? (Player) sender : null, placeholder)); sender.sendMessage(placeholder + ": " + plugin.getPlaceholders().getExpansion().placeholder(sender instanceof Player ? (Player) sender : null, placeholder));
} }
return true; return true;
} else if (args[0].equalsIgnoreCase("tree") && sender.hasPermission("rankup.admin")) { } else if (args[0].equalsIgnoreCase("tree") && sender.hasPermission("rankup.admin")) {
@@ -1,6 +1,7 @@
package sh.okx.rankup.commands; package sh.okx.rankup.commands;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -62,7 +63,12 @@ public class PrestigeCommand implements CommandExecutor {
.send(player); .send(player);
break; break;
case "gui": case "gui":
Gui.of(player, prestige, rankElement.getNext().getRank(), plugin).open(player); Gui gui = Gui.of(player, prestige, rankElement.getNext().getRank(), plugin);
if (gui == null) {
player.sendMessage(ChatColor.RED + "GUI is not available. Check console for more informatiopn.");
return true;
}
gui.open(player);
break; break;
case "none": case "none":
plugin.getHelper().prestige(player); plugin.getHelper().prestige(player);
@@ -1,6 +1,7 @@
package sh.okx.rankup.commands; package sh.okx.rankup.commands;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.ChatColor;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -40,13 +41,6 @@ public class RankupCommand implements CommandExecutor {
return true; return true;
} }
RankElement<Rank> rankElement = rankups.getByPlayer(player); RankElement<Rank> rankElement = rankups.getByPlayer(player);
/*Rank next = rankups.next(rank);
if (next == null) {
plugin.getLogger().severe("Rankup from " + rank.getRank() + " to " + rank.getNext() +
" is defined but " + rank.getNext() + " does not exist.");
plugin.getMessage(Message.INVALID_RANKUP).failIfEmpty().send(player);
return true;
}*/
FileConfiguration config = plugin.getConfig(); FileConfiguration config = plugin.getConfig();
String confirmationType = config.getString("confirmation-type").toLowerCase(); String confirmationType = config.getString("confirmation-type").toLowerCase();
@@ -68,7 +62,12 @@ public class RankupCommand implements CommandExecutor {
.send(player); .send(player);
break; break;
case "gui": case "gui":
Gui.of(player, rankElement.getRank(), rankElement.getNext().getRank(), plugin).open(player); Gui gui = Gui.of(player, rankElement.getRank(), rankElement.getNext().getRank(), plugin);
if (gui == null) {
player.sendMessage(ChatColor.RED + "GUI is not available. Check console for more informatiopn.");
return true;
}
gui.open(player);
break; break;
case "none": case "none":
plugin.getHelper().rankup(player); plugin.getHelper().rankup(player);
@@ -1,4 +1,9 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
import org.bukkit.entity.Player;
public interface Economy { public interface Economy {
double getBalance(Player player);
void withdrawPlayer(Player player, double amount);
void setPlayer(Player player, double amount);
} }
@@ -1,4 +1,5 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
public interface EconomyProvider { public interface EconomyProvider {
Economy getEconomy();
} }
@@ -1,4 +1,27 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
public class VaultEconomy { import org.bukkit.entity.Player;
public class VaultEconomy implements Economy {
private final net.milkbowl.vault.economy.Economy economy;
public VaultEconomy(net.milkbowl.vault.economy.Economy economy) {
this.economy = economy;
}
@Override
public double getBalance(Player player) {
return economy.getBalance(player);
}
@Override
public void withdrawPlayer(Player player, double amount) {
economy.withdrawPlayer(player, amount);
}
@Override
public void setPlayer(Player player, double amount) {
throw new UnsupportedOperationException();
}
} }
@@ -1,4 +1,17 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
public class VaultEconomyProvider { import org.bukkit.Bukkit;
import org.bukkit.plugin.RegisteredServiceProvider;
public class VaultEconomyProvider implements EconomyProvider {
@Override
public Economy getEconomy() {
RegisteredServiceProvider<net.milkbowl.vault.economy.Economy> rsp = Bukkit.getServer().getServicesManager()
.getRegistration(net.milkbowl.vault.economy.Economy.class);
if (rsp != null) {
return new VaultEconomy(rsp.getProvider());
} else {
return null;
}
}
} }
+5
View File
@@ -41,6 +41,11 @@ public class Gui implements InventoryHolder {
String type = gui.prestige ? "prestige" : "rankup"; String type = gui.prestige ? "prestige" : "rankup";
String basePath = type + ".gui"; String basePath = type + ".gui";
ConfigurationSection config = plugin.getSection(oldRank, basePath); ConfigurationSection config = plugin.getSection(oldRank, basePath);
if (config == null) {
plugin.getLogger().severe("You must update your config.yml and locale/en.yml to be able to use the GUI! Your configuration files are outdated.");
return null;
}
ItemStack[] items = new ItemStack[config.getInt("rows", 1) * 9]; ItemStack[] items = new ItemStack[config.getInt("rows", 1) * 9];
ItemStack fill = getItem(plugin, plugin.getSection(oldRank, basePath + ".fill"), player, oldRank, rank); ItemStack fill = getItem(plugin, plugin.getSection(oldRank, basePath + ".fill"), player, oldRank, rank);
@@ -1,6 +1,7 @@
package sh.okx.rankup.hook; package sh.okx.rankup.hook;
public interface PermisionManager { public interface PermissionManager {
GroupProvider findPermissionProvider(); GroupProvider findPermissionProvider();
GroupProvider permissionOnlyProvider(); GroupProvider permissionOnlyProvider();
@@ -4,13 +4,14 @@ import net.milkbowl.vault.permission.Permission;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.RankupPlugin;
public class PermissionManager { public class VaultPermissionManager implements PermissionManager {
private final RankupPlugin plugin; private final RankupPlugin plugin;
public PermissionManager(RankupPlugin plugin) { public VaultPermissionManager(RankupPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Override
public GroupProvider findPermissionProvider() { public GroupProvider findPermissionProvider() {
return getVaultPermissionProvider(); return getVaultPermissionProvider();
} }
@@ -28,6 +29,7 @@ public class PermissionManager {
return new VaultGroupProvider(provider); return new VaultGroupProvider(provider);
} }
@Override
public GroupProvider permissionOnlyProvider() { public GroupProvider permissionOnlyProvider() {
return new PermissionGroupProvider(); return new PermissionGroupProvider();
} }
@@ -1,4 +1,7 @@
package sh.okx.rankup.placeholders; package sh.okx.rankup.placeholders;
public class Expansion { import org.bukkit.entity.Player;
public interface Expansion {
String placeholder(Player player, String placeholder);
} }
@@ -27,9 +27,10 @@ public class Placeholders {
} }
public void register() { public void register() {
expansion = new RankupExpansion(plugin, this);
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
expansion = new RankupExpansion(plugin, this); RankupPlaceholderExpansion placeholderExpansion = new RankupPlaceholderExpansion(plugin, expansion);
expansion.register(); placeholderExpansion.register();
registered = true; registered = true;
} else { } else {
registered = false; registered = false;
@@ -1,4 +1,218 @@
package sh.okx.rankup.placeholders; package sh.okx.rankup.placeholders;
public class RankupExpansion { import lombok.RequiredArgsConstructor;
import org.bukkit.entity.Player;
import sh.okx.rankup.RankupPlugin;
import sh.okx.rankup.prestige.Prestige;
import sh.okx.rankup.prestige.Prestiges;
import sh.okx.rankup.ranks.Rank;
import sh.okx.rankup.ranks.RankElement;
import sh.okx.rankup.ranks.Rankups;
import sh.okx.rankup.requirements.Requirement;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@RequiredArgsConstructor
public class RankupExpansion implements Expansion {
private static final Pattern PATTERN = Pattern.compile("(.*)#(.*)");
private final RankupPlugin plugin;
private final Placeholders placeholders;
@Override
public String placeholder(Player player, String params) {
if (player == null) {
return "";
}
params = params.toLowerCase();
Rankups rankups = plugin.getRankups();
RankElement<Rank> rankElement = rankups.getByPlayer(player);
Rank rank = rankElement == null ? null : rankElement.getRank();
Prestiges prestiges = plugin.getPrestiges();
RankElement<Prestige> prestigeElement = null;
Prestige prestige = null;
if (prestiges != null) {
prestigeElement = prestiges.getByPlayer(player);
prestige = prestigeElement == null ? null : prestigeElement.getRank();
}
if (params.startsWith("requirement_")) {
String[] parts = params.split("_", 3);
return getPlaceholderRequirement(player, rank,
replacePattern(parts[1]), parts.length > 2 ? parts[2] : "");
} else if (params.startsWith("rank_requirement_")) {
String[] parts = params.split("_", 5);
return getPlaceholderRequirement(player, rankups.getByName(parts[2]),
replacePattern(parts[3]), parts.length > 4 ? parts[4] : "");
// return placeholders.getSimpleFormat().format(orElse(rankups.getByName(parts[2]).getRequirement(parts[3]), Requirement::getValueDouble, 0));
} else if (params.startsWith("rank_money_")) {
String[] parts = params.split("_", 4);
double amount = Objects.requireNonNull(rankups.getByName(parts[2]), "Rankup " + parts[2] + " does not exist").getRequirement(player, "money").getValueDouble();
if (parts.length > 3 && parts[3].equalsIgnoreCase("left")) {
amount = amount - plugin.getEconomy().getBalance(player);
}
return plugin.formatMoney(Math.max(0, amount));
} else if (params.startsWith("status_")) {
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<Rank> 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) {
case "current_prestige":
requirePrestiging(prestiges, params);
if (prestige == null || prestige.getRank() == null) {
return getPlaceholder("no-prestige");
} else {
return prestige.getRank();
}
case "next_prestige":
requirePrestiging(prestiges, params);
if (prestigeElement != null && !prestigeElement.hasNext()) {
return getPlaceholder("highest-rank");
}
return orElse(prestige, Prestige::getNext, prestiges.getFirst().getNext());
case "prestige_money":
requirePrestiging(prestiges, params);
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));
case "current_rank":
if (rank == null) {
return getPlaceholder("not-in-ladder");
} else {
return rank.getRank();
}
case "next_rank":
if (rankElement != null && !rankElement.hasNext()) {
return getPlaceholder("highest-rank");
}
return orElsePlaceholder(rank, r -> orElsePlaceholder(rank, Rank::getNext, "highest-rank"), "not-in-ladder");
case "money":
return String.valueOf(getMoney(player, rank));
case "money_formatted":
return plugin.formatMoney(getMoney(player, rank).doubleValue());
case "money_left":
return String.valueOf(Math.max(0, orElse(rank, r -> simplify(plugin.getEconomy().getBalance(player) - r.getRequirement(player, "money").getValueDouble()), 0).doubleValue()));
case "money_left_formatted":
return plugin.formatMoney(Math.max(0D, orElse(rank, r -> plugin.getEconomy().getBalance(player) - r.getRequirement(player, "money").getValueDouble(), 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":
return placeholders.getPercentFormat().format(Math.max(0D, orElse(rank, r -> (1 - (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble())) * 100, 0).doubleValue()));
case "percent_done":
return String.valueOf(Math.min(100D, orElse(rank, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
case "percent_done_formatted":
return placeholders.getPercentFormat().format(Math.min(100D, orElse(rank, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
case "prestige_percent_left_formatted":
return placeholders.getPercentFormat().format(Math.max(0D, orElse(prestige, r -> (1 - (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble())) * 100, 0).doubleValue()));
case "prestige_percent_done_formatted":
return placeholders.getPercentFormat().format(Math.min(100D, orElse(prestige, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
default:
return null;
}
}
private Number getMoney(Player player, Rank rank) {
return orElse(rank, r -> simplify(r.getRequirement(player, "money").getValueDouble()), 0);
}
private void requirePrestiging(Prestiges prestiges, String params) {
Objects.requireNonNull(prestiges, "Using %rankup_" + params + "% prestige placeholder but prestiging is disabled.");
}
private String getPlaceholderRequirement(Player player, Rank rank, String requirementName, String params) {
if (rank == null) {
return "";
}
Requirement requirement = rank.getRequirement(player, requirementName);
switch (params) {
case "":
return orElse(requirement, Requirement::getValueString, "0");
case "left":
return placeholders.getSimpleFormat().format(orElse(requirement, r -> r.getRemaining(player), 0));
case "done":
return placeholders.getSimpleFormat().format(orElse(requirement, r -> r.getValueDouble() - r.getRemaining(player), 0));
case "percent_left":
return placeholders.getPercentFormat().format(orElse(requirement, r -> (r.getRemaining(player) / r.getValueDouble()) * 100, 0));
case "percent_done":
return placeholders.getPercentFormat().format(orElse(requirement, r -> (1 - (r.getRemaining(player) / r.getValueDouble())) * 100, 100));
default:
return null;
}
}
private Number simplify(Number number) {
if (number instanceof Float) {
return (float) number % 1 == 0 ? number.intValue() : number;
} else if (number instanceof Double) {
return (double) number % 1 == 0 ? number.longValue() : number;
} else {
return number;
}
}
private <T> String orElsePlaceholder(T t, Function<T, Object> value, Object fallback) {
if (t == null) {
return getPlaceholder(String.valueOf(fallback));
}
try {
return String.valueOf(value.apply(t));
} catch (NullPointerException ex) {
return getPlaceholder(String.valueOf(fallback));
}
}
private <T, R> R orElse(T t, Function<T, R> value, R fallback) {
if (t == null) {
return fallback;
}
try {
return value.apply(t);
} catch (NullPointerException ex) {
return fallback;
}
}
private String replacePattern(String string) {
Matcher matcher = PATTERN.matcher(string);
if (matcher.matches()) {
return matcher.group(1) + "#" + matcher.group(2).replace("-", "_");
} else {
return string;
}
}
private String getPlaceholder(String name) {
return plugin.getConfig().getString("placeholders." + name);
}
} }
@@ -4,217 +4,15 @@ import lombok.RequiredArgsConstructor;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.RankupPlugin;
import sh.okx.rankup.prestige.Prestige;
import sh.okx.rankup.prestige.Prestiges;
import sh.okx.rankup.ranks.Rank;
import sh.okx.rankup.ranks.RankElement;
import sh.okx.rankup.ranks.Rankups;
import sh.okx.rankup.requirements.Requirement;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@RequiredArgsConstructor @RequiredArgsConstructor
public class RankupExpansion extends PlaceholderExpansion { public class RankupPlaceholderExpansion extends PlaceholderExpansion {
private static final Pattern PATTERN = Pattern.compile("(.*)#(.*)");
private final RankupPlugin plugin; private final RankupPlugin plugin;
private final Placeholders placeholders; private final RankupExpansion expansion;
@Override @Override
public String onPlaceholderRequest(Player player, String params) { public String onPlaceholderRequest(Player player, String params) {
if (player == null) { return expansion.placeholder(player, params);
return "";
}
params = params.toLowerCase();
Rankups rankups = plugin.getRankups();
RankElement<Rank> rankElement = rankups.getByPlayer(player);
Rank rank = rankElement == null ? null : rankElement.getRank();
Prestiges prestiges = plugin.getPrestiges();
RankElement<Prestige> prestigeElement = null;
Prestige prestige = null;
if (prestiges != null) {
prestigeElement = prestiges.getByPlayer(player);
prestige = prestigeElement == null ? null : prestigeElement.getRank();
}
if (params.startsWith("requirement_")) {
String[] parts = params.split("_", 3);
return getPlaceholderRequirement(player, rank,
replacePattern(parts[1]), parts.length > 2 ? parts[2] : "");
} else if (params.startsWith("rank_requirement_")) {
String[] parts = params.split("_", 5);
return getPlaceholderRequirement(player, rankups.getByName(parts[2]),
replacePattern(parts[3]), parts.length > 4 ? parts[4] : "");
// return placeholders.getSimpleFormat().format(orElse(rankups.getByName(parts[2]).getRequirement(parts[3]), Requirement::getValueDouble, 0));
} else if (params.startsWith("rank_money_")) {
String[] parts = params.split("_", 4);
double amount = Objects.requireNonNull(rankups.getByName(parts[2]), "Rankup " + parts[2] + " does not exist").getRequirement(player, "money").getValueDouble();
if (parts.length > 3 && parts[3].equalsIgnoreCase("left")) {
amount = amount - plugin.getEconomy().getBalance(player);
}
return plugin.formatMoney(Math.max(0, amount));
} else if (params.startsWith("status_")) {
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<Rank> 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) {
case "current_prestige":
requirePrestiging(prestiges, params);
if (prestige == null || prestige.getRank() == null) {
return getPlaceholder("no-prestige");
} else {
return prestige.getRank();
}
case "next_prestige":
requirePrestiging(prestiges, params);
if (prestigeElement != null && !prestigeElement.hasNext()) {
return getPlaceholder("highest-rank");
}
return orElse(prestige, Prestige::getNext, prestiges.getFirst().getNext());
case "prestige_money":
requirePrestiging(prestiges, params);
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));
case "current_rank":
if (rank == null) {
return getPlaceholder("not-in-ladder");
} else {
return rank.getRank();
}
case "next_rank":
if (rankElement != null && !rankElement.hasNext()) {
return getPlaceholder("highest-rank");
}
return orElsePlaceholder(rank, r -> orElsePlaceholder(rank, Rank::getNext, "highest-rank"), "not-in-ladder");
case "money":
return String.valueOf(getMoney(player, rank));
case "money_formatted":
return plugin.formatMoney(getMoney(player, rank).doubleValue());
case "money_left":
return String.valueOf(Math.max(0, orElse(rank, r -> simplify(plugin.getEconomy().getBalance(player) - r.getRequirement(player, "money").getValueDouble()), 0).doubleValue()));
case "money_left_formatted":
return plugin.formatMoney(Math.max(0D, orElse(rank, r -> plugin.getEconomy().getBalance(player) - r.getRequirement(player, "money").getValueDouble(), 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":
return placeholders.getPercentFormat().format(Math.max(0D, orElse(rank, r -> (1 - (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble())) * 100, 0).doubleValue()));
case "percent_done":
return String.valueOf(Math.min(100D, orElse(rank, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
case "percent_done_formatted":
return placeholders.getPercentFormat().format(Math.min(100D, orElse(rank, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
case "prestige_percent_left_formatted":
return placeholders.getPercentFormat().format(Math.max(0D, orElse(prestige, r -> (1 - (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble())) * 100, 0).doubleValue()));
case "prestige_percent_done_formatted":
return placeholders.getPercentFormat().format(Math.min(100D, orElse(prestige, r -> (plugin.getEconomy().getBalance(player) / r.getRequirement(player, "money").getValueDouble()) * 100, 0).doubleValue()));
default:
return null;
}
}
private Number getMoney(Player player, Rank rank) {
return orElse(rank, r -> simplify(r.getRequirement(player, "money").getValueDouble()), 0);
}
private void requirePrestiging(Prestiges prestiges, String params) {
Objects.requireNonNull(prestiges, "Using %rankup_" + params + "% prestige placeholder but prestiging is disabled.");
}
private String getPlaceholderRequirement(Player player, Rank rank, String requirementName, String params) {
if (rank == null) {
return "";
}
Requirement requirement = rank.getRequirement(player, requirementName);
switch (params) {
case "":
return orElse(requirement, Requirement::getValueString, "0");
case "left":
return placeholders.getSimpleFormat().format(orElse(requirement, r -> r.getRemaining(player), 0));
case "done":
return placeholders.getSimpleFormat().format(orElse(requirement, r -> r.getValueDouble() - r.getRemaining(player), 0));
case "percent_left":
return placeholders.getPercentFormat().format(orElse(requirement, r -> (r.getRemaining(player) / r.getValueDouble()) * 100, 0));
case "percent_done":
return placeholders.getPercentFormat().format(orElse(requirement, r -> (1 - (r.getRemaining(player) / r.getValueDouble())) * 100, 100));
default:
return null;
}
}
private Number simplify(Number number) {
if (number instanceof Float) {
return (float) number % 1 == 0 ? number.intValue() : number;
} else if (number instanceof Double) {
return (double) number % 1 == 0 ? number.longValue() : number;
} else {
return number;
}
}
private <T> String orElsePlaceholder(T t, Function<T, Object> value, Object fallback) {
if (t == null) {
return getPlaceholder(String.valueOf(fallback));
}
try {
return String.valueOf(value.apply(t));
} catch (NullPointerException ex) {
return getPlaceholder(String.valueOf(fallback));
}
}
private <T, R> R orElse(T t, Function<T, R> value, R fallback) {
if (t == null) {
return fallback;
}
try {
return value.apply(t);
} catch (NullPointerException ex) {
return fallback;
}
}
private String replacePattern(String string) {
Matcher matcher = PATTERN.matcher(string);
if (matcher.matches()) {
return matcher.group(1) + "#" + matcher.group(2).replace("-", "_");
} else {
return string;
}
}
private String getPlaceholder(String name) {
return plugin.getConfig().getString("placeholders." + name);
} }
@Override @Override
@@ -1,4 +1,57 @@
package sh.okx.rankup.requirements.requirement; package sh.okx.rankup.requirements.requirement;
public class AdvancementRequirement { import org.bukkit.Bukkit;
import org.bukkit.advancement.Advancement;
import org.bukkit.advancement.AdvancementProgress;
import org.bukkit.entity.Player;
import sh.okx.rankup.RankupPlugin;
import sh.okx.rankup.requirements.Requirement;
import java.util.Iterator;
import java.util.regex.Pattern;
/**
* Advancement requirement
* @author Link, with modifications from Okx
*/
public class AdvancementRequirement extends Requirement {
public AdvancementRequirement(RankupPlugin plugin) {
super(plugin, "advancement");
}
protected AdvancementRequirement(Requirement clone) {
super(clone);
}
@Override
public boolean check(Player player) {
for (String string : getValuesString()) {
Iterator<Advancement> advancementIterator = Bukkit.advancementIterator();
while (advancementIterator.hasNext()) {
Advancement adv = advancementIterator.next();
String key = adv.getKey().getKey();
Pattern pattern = Pattern.compile(string.replace("*", ".*").replace("-", ""));
boolean positive = false;
if (pattern.matcher(key).find()) {
positive = !string.startsWith("-");
}
AdvancementProgress progress = player.getAdvancementProgress(adv);
if (progress.isDone() == positive) {
return true;
}
}
}
return false;
}
@Override
public Requirement clone() {
return new AdvancementRequirement(this);
}
@Override
public double getValueDouble() {
return 1;
}
} }
@@ -1,8 +1,8 @@
package sh.okx.rankup.requirements.requirement; package sh.okx.rankup.requirements.requirement;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.RankupPlugin;
import sh.okx.rankup.economy.Economy;
import sh.okx.rankup.requirements.DeductibleRequirement; import sh.okx.rankup.requirements.DeductibleRequirement;
import sh.okx.rankup.requirements.Requirement; import sh.okx.rankup.requirements.Requirement;
@@ -1,8 +1,9 @@
package sh.okx.rankup.requirements; package sh.okx.rankup.requirements.requirement;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import sh.okx.rankup.RankupPlugin; import sh.okx.rankup.RankupPlugin;
import sh.okx.rankup.requirements.requirement.XpLevelRequirement; import sh.okx.rankup.requirements.DeductibleRequirement;
import sh.okx.rankup.requirements.Requirement;
public class XpLevelDeductibleRequirement extends XpLevelRequirement implements DeductibleRequirement { public class XpLevelDeductibleRequirement extends XpLevelRequirement implements DeductibleRequirement {
@@ -1,4 +1,55 @@
package sh.okx.rankup; package sh.okx.rankup;
public class RankupPlaceholderTest { import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.Test;
import sh.okx.rankup.placeholders.RankupExpansion;
import static org.junit.Assert.assertEquals;
public class RankupPlaceholderTest extends RankupTest {
@Test
public void testCurrentRank() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "C");
RankupExpansion expansion = plugin.getPlaceholders().getExpansion();
assertEquals("C", expansion.placeholder(player, "current_rank"));
}
@Test
public void testNextRank() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "C");
RankupExpansion expansion = plugin.getPlaceholders().getExpansion();
assertEquals("D", expansion.placeholder(player, "next_rank"));
}
@Test
public void testStatusCurrent() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "B");
RankupExpansion expansion = plugin.getPlaceholders().getExpansion();
assertEquals("Current", expansion.placeholder(player, "status_b"));
}
@Test
public void testStatusComplete() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "D");
RankupExpansion expansion = plugin.getPlaceholders().getExpansion();
assertEquals("Complete", expansion.placeholder(player, "status_b"));
}
@Test
public void testStatusIncomplete() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "A");
RankupExpansion expansion = plugin.getPlaceholders().getExpansion();
assertEquals("Incomplete", expansion.placeholder(player, "status_b"));
}
} }
@@ -1,4 +1,101 @@
package sh.okx.rankup; package sh.okx.rankup;
import be.seeseemelk.mockbukkit.MockBukkit;
import be.seeseemelk.mockbukkit.ServerMock;
import be.seeseemelk.mockbukkit.entity.PlayerMock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import sh.okx.rankup.economy.TestEconomyProvider;
import sh.okx.rankup.hook.GroupProvider;
import sh.okx.rankup.hook.TestGroupProvider;
import sh.okx.rankup.hook.TestPermissionManager;
import sh.okx.rankup.messages.Message;
import sh.okx.rankup.messages.Variable;
import sh.okx.rankup.ranks.Rank;
import sh.okx.rankup.ranks.RankElement;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class RankupTest { public class RankupTest {
protected GroupProvider groupProvider;
protected ServerMock server;
protected RankupPlugin plugin;
@Before
public void setup() {
System.setProperty("TEST", "true");
try {
groupProvider = new TestGroupProvider();
server = MockBukkit.mock();
plugin = MockBukkit.load(RankupPlugin.class, new TestPermissionManager(groupProvider), new TestEconomyProvider());
// let rankup finish setting up
server.getScheduler().performTicks(1);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testAutoRankup() {
PlayerMock player = server.addPlayer();
// requirement of $1000
plugin.getEconomy().setPlayer(player, 1000);
// give them group A
groupProvider.addGroup(player.getUniqueId(), "A");
// give the permission to auto rankup
player.addAttachment(plugin, "rankup.auto", true);
plugin.autoRankup.run();
assertTrue(groupProvider.inGroup(player.getUniqueId(), "B"));
assertEquals(0, plugin.getEconomy().getBalance(player), 0);
}
@Test
public void testNotInLadder() {
PlayerMock player = server.addPlayer();
plugin.getHelper().rankup(player);
player.assertSaid(plugin.getMessage(Message.NOT_IN_LADDER).replace(Variable.PLAYER, player.getName()).toString());
player.assertNoMoreSaid();
}
@Test
public void testLastRank() {
PlayerMock player = server.addPlayer();
groupProvider.addGroup(player.getUniqueId(), "D");
plugin.getHelper().rankup(player);
player.assertSaid(plugin.getMessage(Message.NO_RANKUP).replaceRanks(player, plugin.getRankups().getTree().last().getRank().getRank()).toString());
player.assertNoMoreSaid();
}
@Test
public void testMoneyRequirement() {
PlayerMock player = server.addPlayer();
plugin.getEconomy().setPlayer(player, 500);
groupProvider.addGroup(player.getUniqueId(), "A");
plugin.getHelper().rankup(player);
RankElement<Rank> element = plugin.getRankups().getTree().getFirst();
Rank rank = element.getRank();
player.assertSaid(plugin.replaceMoneyRequirements(plugin.getMessage(rank, Message.REQUIREMENTS_NOT_MET).replaceRanks(player, rank, element.getNext().getRank()), player, rank).toString());
player.assertNoMoreSaid();
}
@After
public void tearDown() {
MockBukkit.unmock();
System.clearProperty("TEST");
}
} }
@@ -1,4 +1,25 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
public class TestEconomy { import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TestEconomy implements Economy {
private final Map<UUID, Double> balances = new HashMap<>();
@Override
public double getBalance(Player player) {
return balances.get(player.getUniqueId());
}
@Override
public void withdrawPlayer(Player player, double amount) {
balances.put(player.getUniqueId(), balances.getOrDefault(player.getUniqueId(), 0D) - amount);
}
public void setPlayer(Player player, double amount) {
balances.put(player.getUniqueId(), amount);
}
} }
@@ -1,4 +1,8 @@
package sh.okx.rankup.economy; package sh.okx.rankup.economy;
public class TestEconomyProvider { public class TestEconomyProvider implements EconomyProvider {
@Override
public Economy getEconomy() {
return new TestEconomy();
}
} }
@@ -1,4 +1,25 @@
package sh.okx.rankup.hook; package sh.okx.rankup.hook;
public class TestGroupProvider { import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.UUID;
public class TestGroupProvider implements GroupProvider {
private Multimap<UUID, String> groups = ArrayListMultimap.create();
@Override
public boolean inGroup(UUID uuid, String group) {
return groups.containsEntry(uuid, group.toLowerCase());
}
@Override
public void addGroup(UUID uuid, String group) {
groups.put(uuid, group.toLowerCase());
}
@Override
public void removeGroup(UUID uuid, String group) {
groups.remove(uuid, group.toLowerCase());
}
} }
@@ -1,4 +1,19 @@
package sh.okx.rankup.hook; package sh.okx.rankup.hook;
public class TestPermissionManager { public class TestPermissionManager implements PermissionManager {
private final GroupProvider groupProvider;
public TestPermissionManager(GroupProvider groupProvider) {
this.groupProvider = groupProvider;
}
@Override
public GroupProvider findPermissionProvider() {
return groupProvider;
}
@Override
public GroupProvider permissionOnlyProvider() {
return groupProvider;
}
} }
@@ -5,7 +5,6 @@ import org.junit.Test;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
public class MessageBuilderTest { public class MessageBuilderTest {
@Test @Test
public void testFailIfEmpty() { public void testFailIfEmpty() {