From c53fece28f7c1ad7a9d16c255188a2c710593f8d Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 28 Sep 2019 13:48:24 +0200 Subject: [PATCH 01/12] Added WorldSettings to run commands on island creation/join and deletion/leave Implements https://github.com/BentoBoxWorld/BentoBox/issues/704 Gamemode addons will need to be updated to use the new WorldSettings, which have been properly documented so it should be easy to write down comments about them. --- .../commands/admin/AdminDeleteCommand.java | 12 +++++ .../commands/island/IslandResetCommand.java | 12 +++++ .../island/team/IslandTeamKickCommand.java | 11 +++++ .../island/team/IslandTeamLeaveCommand.java | 11 +++++ .../api/configuration/WorldSettings.java | 45 +++++++++++++++++++ .../bentobox/managers/IslandWorldManager.java | 24 ++++++++++ .../bentobox/managers/IslandsManager.java | 12 ++++- 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java index 10979c484..b77eea8bc 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommand.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import org.bukkit.Bukkit; import org.bukkit.util.Vector; import world.bentobox.bentobox.api.commands.CompositeCommand; @@ -76,6 +77,17 @@ public class AdminDeleteCommand extends ConfirmableCommand { // Remove them from this island (it still exists and will be deleted later) getIslands().removePlayer(getWorld(), targetUUID); if (target.isOnline()) { + // Execute commands when leaving + getIWM().getOnLeaveCommands(getWorld()).forEach(command -> { + command = command.replace("[player]", target.getName()); + if (command.startsWith("[SUDO]")) { + // Execute the command by the player + target.performCommand(command.substring(6)); + } else { + // Otherwise execute as the server console + getPlugin().getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); // Remove money inventory etc. if (getIWM().isOnLeaveResetEnderChest(getWorld())) { target.getPlayer().getEnderChest().clear(); diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java index 87e984491..0a5472353 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandResetCommand.java @@ -167,6 +167,18 @@ public class IslandResetCommand extends ConfirmableCommand { // Remove player getIslands().removePlayer(getWorld(), memberUUID); + // Execute commands when leaving + getIWM().getOnLeaveCommands(island.getWorld()).forEach(command -> { + command = command.replace("[player]", member.getName()); + if (command.startsWith("[SUDO]") && member.isOnline()) { + // Execute the command by the player + member.performCommand(command.substring(6)); + } else { + // Otherwise execute as the server console + getPlugin().getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); + // Remove money inventory etc. if (getIWM().isOnLeaveResetEnderChest(getWorld())) { if (member.isOnline()) { diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java index e663a6dd6..09d403f56 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamKickCommand.java @@ -78,6 +78,17 @@ public class IslandTeamKickCommand extends ConfirmableCommand { target.sendMessage("commands.island.team.kick.owner-kicked", "[gamemode]", getAddon().getDescription().getName()); Island oldIsland = getIslands().getIsland(getWorld(), targetUUID); getIslands().removePlayer(getWorld(), targetUUID); + // Execute commands when leaving + getIWM().getOnLeaveCommands(oldIsland.getWorld()).forEach(command -> { + command = command.replace("[player]", target.getName()); + if (command.startsWith("[SUDO]") && target.isOnline()) { + // Execute the command by the player + target.performCommand(command.substring(6)); + } else { + // Otherwise execute as the server console + getPlugin().getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); // Remove money inventory etc. if (getIWM().isOnLeaveResetEnderChest(getWorld())) { if (target.isOnline()) { diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java index 4c5577aee..8440e1207 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamLeaveCommand.java @@ -72,6 +72,17 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand { User.getInstance(ownerUUID).sendMessage("commands.island.team.leave.left-your-island", TextVariables.NAME, user.getName()); } getIslands().setLeaveTeam(getWorld(), user.getUniqueId()); + // Execute commands when leaving + getIWM().getOnLeaveCommands(island.getWorld()).forEach(command -> { + command = command.replace("[player]", user.getName()); + if (command.startsWith("[SUDO]") && user.isOnline()) { + // Execute the command by the player + user.performCommand(command.substring(6)); + } else { + // Otherwise execute as the server console + getPlugin().getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); // Remove money inventory etc. if (getIWM().isOnLeaveResetEnderChest(getWorld())) { user.getPlayer().getEnderChest().clear(); diff --git a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java index 9ad5b2130..b00d8b2fe 100644 --- a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java +++ b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java @@ -8,6 +8,7 @@ import org.bukkit.Difficulty; import org.bukkit.GameMode; import org.bukkit.entity.EntityType; +import org.eclipse.jdt.annotation.NonNull; import world.bentobox.bentobox.api.flags.Flag; /** @@ -186,6 +187,27 @@ public interface WorldSettings extends ConfigObject { */ boolean isOnJoinResetMoney(); + /** + * Returns a list of commands that should be executed when the player joins an island or creates one.
+ * These commands are executed by the console, unless otherwise stated using the {@code [SUDO]} prefix, in which case they are executed by the player.
+ *
+ * Available placeholders for the commands are the following: + * + *
+ * Here are some examples of valid commands to execute: + * + * @return a list of commands. + * @since 1.8.0 + * @see #getOnLeaveCommands() + */ + @NonNull + List getOnJoinCommands(); + /** * @return the onLeaveResetEnderChest */ @@ -201,6 +223,29 @@ public interface WorldSettings extends ConfigObject { */ boolean isOnLeaveResetMoney(); + /** + * Returns a list of commands that should be executed when the player leaves an island or resets one.
+ * These commands are executed by the console, unless otherwise stated using the {@code [SUDO]} prefix, in which case they are executed by the player.
+ *
+ * Available placeholders for the commands are the following: + * + *
+ * Here are some examples of valid commands to execute: + * + *
+ * Note that player-executed commands might not work, as these commands can be run with said player being offline. + * @return a list of commands. + * @since 1.8.0 + * @see #getOnJoinCommands() + */ + @NonNull + List getOnLeaveCommands(); + /** * @return true if the default world generator should not operate in this world */ diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandWorldManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandWorldManager.java index b47af1e61..2b6df65ac 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandWorldManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandWorldManager.java @@ -562,6 +562,18 @@ public class IslandWorldManager { return gameModes.get(world).getWorldSettings().isOnJoinResetEnderChest(); } + /** + * Returns a list of commands to execute when the player creates or joins an island. + * @param world the World + * @return a list of commands + * @since 1.8.0 + * @see #getOnLeaveCommands(World) + */ + @NonNull + public List getOnJoinCommands(@NonNull World world) { + return gameModes.get(world).getWorldSettings().getOnJoinCommands(); + } + /** * @return the onLeaveResetMoney */ @@ -583,6 +595,18 @@ public class IslandWorldManager { return gameModes.get(world).getWorldSettings().isOnLeaveResetEnderChest(); } + /** + * Returns a list of commands to execute when the player resets or leaves an island. + * @param world the World + * @return a list of commands + * @since 1.8.0 + * @see #getOnJoinCommands(World) + */ + @NonNull + public List getOnLeaveCommands(@NonNull World world) { + return gameModes.get(world).getWorldSettings().getOnLeaveCommands(); + } + /** * Get data folder for the addon that registered this world * diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java index ca2456d0c..12d4cd80f 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java @@ -670,7 +670,17 @@ public class IslandsManager { } // If this is a new island, then run commands and do resets if (newIsland) { - // TODO add command running + // Execute commands + plugin.getIWM().getOnJoinCommands(world).forEach(command -> { + command = command.replace("[player]", player.getName()); + if (command.startsWith("[SUDO]")) { + // Execute the command by the player + player.performCommand(command.substring(6)); + } else { + // Otherwise execute as the server console + plugin.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); // Remove money inventory etc. if (plugin.getIWM().isOnJoinResetEnderChest(world)) { From 4eae5fada077f8a4608bbc44147f9be6b8bfca3f Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 28 Sep 2019 14:05:58 +0200 Subject: [PATCH 02/12] Fixed tests compilation errors --- .../api/commands/island/IslandGoCommandTest.java | 10 ++++++++++ .../bentobox/listeners/BlockEndDragonTest.java | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java index 6c283a7be..12dfef04e 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandGoCommandTest.java @@ -30,6 +30,7 @@ import org.bukkit.plugin.PluginManager; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; import org.bukkit.util.Vector; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.junit.After; import org.junit.Before; @@ -701,5 +702,14 @@ public class IslandGoCommandTest { return false; } + @Override + public @NonNull List getOnJoinCommands() { + return null; + } + + @Override + public @NonNull List getOnLeaveCommands() { + return null; + } } } diff --git a/src/test/java/world/bentobox/bentobox/listeners/BlockEndDragonTest.java b/src/test/java/world/bentobox/bentobox/listeners/BlockEndDragonTest.java index 773cfbde1..a61e9151f 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/BlockEndDragonTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/BlockEndDragonTest.java @@ -29,6 +29,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.junit.After; import org.junit.Before; @@ -275,6 +276,15 @@ public class BlockEndDragonTest { private Map worldFlags = new HashMap<>(); + @Override + public @NonNull List getOnLeaveCommands() { + return null; + } + + @Override + public @NonNull List getOnJoinCommands() { + return null; + } @Override public GameMode getDefaultGameMode() { From d9dc337de9d03f8b88f84bca59c30e5e781ec5fa Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 28 Sep 2019 14:21:16 +0200 Subject: [PATCH 03/12] Should fix NPE when setting up connection to GitHub --- .../bentobox/managers/WebManager.java | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/managers/WebManager.java b/src/main/java/world/bentobox/bentobox/managers/WebManager.java index bb5afb1a1..c17ad6028 100644 --- a/src/main/java/world/bentobox/bentobox/managers/WebManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/WebManager.java @@ -59,36 +59,27 @@ public class WebManager { if (plugin.getSettings().isLogGithubDownloadData()) { plugin.log("Downloading data from GitHub..."); } - GitHubRepository repo = new GitHubRepository(gh, "BentoBoxWorld/weblink"); + GitHubRepository repo; + try { + repo = new GitHubRepository(gh, "BentoBoxWorld/weblink"); + } catch (Exception e) { + plugin.logError("An unhandled exception occurred when trying to connect to GitHub..."); + plugin.logStacktrace(e); - String tagsContent = ""; - String topicsContent = ""; - String catalogContent = ""; + // Stop the execution of the method right away. + return; + } // Downloading the data - try { - tagsContent = repo.getContent("catalog/tags.json").getContent().replaceAll("\\n", ""); - topicsContent = repo.getContent("catalog/topics.json").getContent().replaceAll("\\n", ""); - catalogContent = repo.getContent("catalog/catalog.json").getContent().replaceAll("\\n", ""); - } catch (IllegalAccessException e) { - if (plugin.getSettings().isLogGithubDownloadData()) { - plugin.log("Could not connect to GitHub."); - } - } catch (Exception e) { - plugin.logError("An unhandled exception occurred when downloading data from GitHub..."); - plugin.logStacktrace(e); - } + String tagsContent = getContent(repo, "catalog/tags.json"); + String topicsContent = getContent(repo, "catalog/topics.json"); + String catalogContent = getContent(repo, "catalog/catalog.json"); // People were concerned that the download took ages, so we need to tell them it's over now. if (plugin.getSettings().isLogGithubDownloadData()) { plugin.log("Successfully downloaded data from GitHub."); } - // Decoding the Base64 encoded contents - tagsContent = new String(Base64.getDecoder().decode(tagsContent), StandardCharsets.UTF_8); - topicsContent = new String(Base64.getDecoder().decode(topicsContent), StandardCharsets.UTF_8); - catalogContent = new String(Base64.getDecoder().decode(catalogContent), StandardCharsets.UTF_8); - /* Parsing the data */ // Register the tags translations in the locales @@ -140,6 +131,29 @@ public class WebManager { }); } + /** + * + * @param repo + * @param fileName + * @return + * @since 1.8.0 + */ + @NonNull + private String getContent(@NonNull GitHubRepository repo, String fileName) { + try { + String content = repo.getContent(fileName).getContent().replaceAll("\\n", ""); + return new String(Base64.getDecoder().decode(content), StandardCharsets.UTF_8); + } catch (IllegalAccessException e) { + if (plugin.getSettings().isLogGithubDownloadData()) { + plugin.log("Could not connect to GitHub."); + } + } catch (Exception e) { + plugin.logError("An unhandled exception occurred when downloading '" + fileName + "' from GitHub..."); + plugin.logStacktrace(e); + } + return ""; + } + /** * Returns the contents of the addons catalog (may be an empty list). * @return the contents of the addons catalog. From 6799c43a0aa9a032f2e91e28f3d128256dc1aa68 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sat, 28 Sep 2019 14:37:29 +0200 Subject: [PATCH 04/12] Added AdminDeathsAddCommand and AdminDeathsRemoveCommand Implements https://github.com/BentoBoxWorld/BentoBox/issues/950 --- .../admin/deaths/AdminDeathsAddCommand.java | 50 +++++++++++++++++++ .../admin/deaths/AdminDeathsCommand.java | 2 + .../deaths/AdminDeathsRemoveCommand.java | 48 ++++++++++++++++++ src/main/resources/locales/en-US.yml | 8 +++ 4 files changed, 108 insertions(+) create mode 100644 src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsAddCommand.java create mode 100644 src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsAddCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsAddCommand.java new file mode 100644 index 000000000..9930f7b79 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsAddCommand.java @@ -0,0 +1,50 @@ +package world.bentobox.bentobox.api.commands.admin.deaths; + +import org.apache.commons.lang.math.NumberUtils; +import org.eclipse.jdt.annotation.NonNull; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; + +import java.util.List; +import java.util.UUID; + +/** + * @since 1.8.0 + * @author Poslovitch + */ +public class AdminDeathsAddCommand extends CompositeCommand { + + public AdminDeathsAddCommand(AdminDeathsCommand parent) { + super(parent, "add"); + } + + @Override + public void setup() { + setDescription("commands.admin.deaths.add.description"); + setParametersHelp("commands.admin.deaths.add.parameters"); + } + + @Override + public boolean execute(User user, String label, @NonNull List args) { + if (args.size() != 2) { + showHelp(this, user); + return false; + } + + UUID target = getPlayers().getUUID(args.get(0)); + if (target == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); + } else { + getPlayers().setDeaths(getWorld(), target, getPlayers().getDeaths(getWorld(), target) + Integer.valueOf(args.get(1))); + user.sendMessage("commands.admin.deaths.add.success", + TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1), + "[total]", String.valueOf(getPlayers().getDeaths(getWorld(), target))); + return true; + } + + return false; + } +} diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsCommand.java index 7adc0b29d..c773af5dc 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsCommand.java @@ -21,6 +21,8 @@ public class AdminDeathsCommand extends CompositeCommand { new AdminDeathsResetCommand(this); new AdminDeathsSetCommand(this); + new AdminDeathsAddCommand(this); + new AdminDeathsRemoveCommand(this); } @Override diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java new file mode 100644 index 000000000..884026da7 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java @@ -0,0 +1,48 @@ +package world.bentobox.bentobox.api.commands.admin.deaths; + +import org.apache.commons.lang.math.NumberUtils; +import org.eclipse.jdt.annotation.NonNull; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; + +import java.util.List; +import java.util.UUID; + +/** + * @since 1.8.0 + * @author Poslovitch + */ +public class AdminDeathsRemoveCommand extends CompositeCommand { + + public AdminDeathsRemoveCommand(AdminDeathsCommand parent) { + super(parent, "remove"); + } + + @Override + public void setup() { + setDescription("commands.admin.deaths.remove.description"); + setParametersHelp("commands.admin.deaths.remove.parameters"); + } + + @Override + public boolean execute(User user, String label, @NonNull List args) { + if (args.size() != 2) { + showHelp(this, user); + return false; + } + + UUID target = getPlayers().getUUID(args.get(0)); + if (target == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); + } else { + getPlayers().setDeaths(getWorld(), target, getPlayers().getDeaths(getWorld(), target) - Integer.valueOf(args.get(1))); + user.sendMessage("commands.admin.deaths.remove.success", TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1)); + return true; + } + + return false; + } +} diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index ead769d91..9078c89bb 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -334,6 +334,14 @@ commands: description: "sets deaths of the player" parameters: " " success: "&aSuccessfully set &b[name]&a's deaths to &b[number]&a." + add: + description: "adds deaths to the player" + parameters: " " + success: "&aSuccessfully added &b[number] &adeaths to &b[name], increasing the total to &b[total]&a deaths." + remove: + description: "removes deaths to the player" + parameters: " " + success: "&aSuccessfully removed &b[number] &adeaths to &b[name], decreasing the total to &b[total]&a deaths." bentobox: description: "BentoBox admin command" about: From f8c4ea568f6e121c3ed152879ebb2991e3ce16a2 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 28 Sep 2019 17:10:30 -0700 Subject: [PATCH 05/12] Adds auto-updating of locale files https://github.com/BentoBoxWorld/BentoBox/issues/960 --- .../bentobox/bentobox/api/addons/Addon.java | 31 +++++- .../bentobox/managers/LocalesManager.java | 94 ++++++++++++++----- 2 files changed, 102 insertions(+), 23 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/addons/Addon.java b/src/main/java/world/bentobox/bentobox/api/addons/Addon.java index f179c3c4c..b3cc4795d 100644 --- a/src/main/java/world/bentobox/bentobox/api/addons/Addon.java +++ b/src/main/java/world/bentobox/bentobox/api/addons/Addon.java @@ -3,6 +3,7 @@ package world.bentobox.bentobox.api.addons; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -12,6 +13,7 @@ import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.Server; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Listener; @@ -244,8 +246,9 @@ public abstract class Addon { * - if true, will overwrite previous file * @param noPath * - if true, the resource's path will be ignored when saving + * @return file written, or null if none */ - public void saveResource(String jarResource, File destinationFolder, boolean replace, boolean noPath) { + public File saveResource(String jarResource, File destinationFolder, boolean replace, boolean noPath) { if (jarResource == null || jarResource.equals("")) { throw new IllegalArgumentException("ResourcePath cannot be null or empty"); } @@ -269,6 +272,7 @@ public abstract class Addon { if (!outFile.exists() || replace) { java.nio.file.Files.copy(in, outFile.toPath()); } + return outFile; } } else { // No file in the jar @@ -279,6 +283,31 @@ public abstract class Addon { BentoBox.getInstance().logError( "Could not save from jar file. From " + jarResource + " to " + destinationFolder.getAbsolutePath()); } + return null; + } + + /** + * Tries to load a YAML file from the Jar + * @param jarResource - YAML file in jar + * @return YamlConfiguration - may be empty + * @throws IOException - if the file cannot be found or loaded from the Jar + * @throws InvalidConfigurationException - if the yaml is malformed + */ + public YamlConfiguration getYamlFromJar(String jarResource) throws IOException, InvalidConfigurationException { + if (jarResource == null || jarResource.equals("")) { + throw new IllegalArgumentException("jarResource cannot be null or empty"); + } + YamlConfiguration result = new YamlConfiguration(); + jarResource = jarResource.replace('\\', '/'); + try (JarFile jar = new JarFile(file)) { + JarEntry jarConfig = jar.getJarEntry(jarResource); + if (jarConfig != null) { + try (InputStreamReader in = new InputStreamReader(jar.getInputStream(jarConfig))) { + result.load(in); + } + } + } + return result; } /** diff --git a/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java b/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java index 9e019be6f..25b23dca7 100644 --- a/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/LocalesManager.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; @@ -15,6 +16,7 @@ import java.util.jar.JarFile; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import world.bentobox.bentobox.BentoBox; @@ -108,7 +110,7 @@ public class LocalesManager { } /** - * Copies locale files from the addon jar to the file system + * Copies locale files from the addon jar to the file system and updates current locales with the latest references * @param addon - addon */ void copyLocalesFromAddonJar(Addon addon) { @@ -116,14 +118,39 @@ public class LocalesManager { File localeDir = new File(plugin.getDataFolder(), LOCALE_FOLDER + File.separator + addon.getDescription().getName()); if (!localeDir.exists()) { localeDir.mkdirs(); - // Obtain any locale files and save them - Util.listJarFiles(jar, LOCALE_FOLDER, ".yml").forEach(lf -> addon.saveResource(lf, localeDir, false, true)); } + // Obtain any locale files, save them and update + Util.listJarFiles(jar, LOCALE_FOLDER, ".yml").forEach(lf -> { + File file = addon.saveResource(lf, localeDir, false, true); + // Update + if (file != null) { + updateLocale(addon, file, lf); + } + }); + } catch (Exception e) { plugin.logError(e.getMessage()); } } + private void updateLocale(Addon addon, File fileLocaleFile, String lf) { + try { + // Load the JAR locale file + YamlConfiguration jarLocale = addon.getYamlFromJar(lf); + // Load the locale file system locale file + YamlConfiguration fileLocale = new YamlConfiguration(); + fileLocale.load(fileLocaleFile); + // Copy new keys to file + jarLocale.getKeys(true).stream().filter(k -> !fileLocale.contains(k, false)).forEach(k -> fileLocale.set(k, jarLocale.get(k))); + // Save file + fileLocale.save(fileLocaleFile); + } catch (Exception e) { + plugin.logError("Error updating locale file: " + lf + " : " + e.getMessage()); + plugin.logStacktrace(e); + } + + } + /** * Copies all the locale files from the plugin jar to the filesystem. * Only done if the locale folder does not already exist. @@ -135,18 +162,36 @@ public class LocalesManager { // If it does exist, then new files will NOT be written! if (!localeDir.exists()) { localeDir.mkdirs(); - FileLister lister = new FileLister(plugin); - try { - for (String name : lister.listJar(LOCALE_FOLDER)) { - // We cannot use Bukkit's saveResource, because we want it to go into a specific folder, so... - // Get the last part of the name - int lastIndex = name.lastIndexOf('/'); - File targetFile = new File(localeDir, name.substring(lastIndex >= 0 ? lastIndex : 0)); - copyFile(name, targetFile); + } + FileLister lister = new FileLister(plugin); + try { + for (String name : lister.listJar(LOCALE_FOLDER)) { + // We cannot use Bukkit's saveResource, because we want it to go into a specific folder, so... + // Get the last part of the name + int lastIndex = name.lastIndexOf('/'); + File targetFile = new File(localeDir, name.substring(lastIndex >= 0 ? lastIndex : 0)); + copyFile(name, targetFile); + // Update the locale file if it exists already + try (InputStreamReader in = new InputStreamReader(plugin.getResource(name))) { + YamlConfiguration jarLocale = new YamlConfiguration(); + jarLocale.load(in); + + YamlConfiguration fileLocale = new YamlConfiguration(); + fileLocale.load(targetFile); + for (String k : jarLocale.getKeys(true)) { + if (!fileLocale.contains(k, false)) { + fileLocale.set(k, jarLocale.get(k)); + } + } + // Save it + fileLocale.save(targetFile); + } catch (InvalidConfigurationException e) { + plugin.logError("Could not update locale files from jar " + e.getMessage()); } - } catch (IOException e) { - plugin.logError("Could not copy locale files from jar " + e.getMessage()); + } + } catch (IOException e) { + plugin.logError("Could not copy locale files from jar " + e.getMessage()); } } @@ -180,9 +225,9 @@ public class LocalesManager { languages.put(localeObject, new BentoBoxLocale(localeObject, languageYaml)); } } catch (Exception e) { - BentoBox.getInstance().logError("Could not load '" + language.getName() + "' : " + e.getMessage() + plugin.logError("Could not load '" + language.getName() + "' : " + e.getMessage() + " with the following cause '" + e.getCause() + "'." + - " The file has likely an invalid YML format or has been made unreadable during the process."); + " The file has likely an invalid YML format or has been made unreadable during the process."); } } } @@ -256,7 +301,11 @@ public class LocalesManager { plugin.log(ChatColor.AQUA + "Analyzing BentoBox locale files"); user.sendRawMessage(ChatColor.AQUA + SPACER); loadLocalesFromFile(BENTOBOX); - analyze(fix); + if (languages.containsKey(Locale.US)) { + analyze(user, fix); + } else { + user.sendRawMessage(ChatColor.RED + "No US English in BentoBox to use for analysis!"); + } user.sendRawMessage(ChatColor.AQUA + "Analyzing Addon locale files"); plugin.getAddonsManager().getAddons().forEach(addon -> { user.sendRawMessage(ChatColor.AQUA + SPACER); @@ -264,22 +313,23 @@ public class LocalesManager { user.sendRawMessage(ChatColor.AQUA + SPACER); languages.clear(); loadLocalesFromFile(addon.getDescription().getName()); - analyze(fix); + if (languages.containsKey(Locale.US)) { + analyze(user, fix); + } else { + user.sendRawMessage(ChatColor.RED + "No US English to use for analysis!"); + } }); reloadLanguages(); } /** * + * @param user * @param fix whether or not locale files with missing translations should be fixed. * Not currently supported. * @since 1.5.0 */ - private void analyze(boolean fix) { - if (!languages.containsKey(Locale.US)) { - return; - } - User user = User.getInstance(Bukkit.getConsoleSender()); + private void analyze(User user, boolean fix) { user.sendRawMessage(ChatColor.GREEN + "The following locales are supported:"); languages.forEach((k,v) -> user.sendRawMessage(ChatColor.GOLD + k.toLanguageTag() + " " + k.getDisplayLanguage() + " " + k.getDisplayCountry())); From e20690935a79401d864f375c7dea54cda9ab3c93 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sun, 29 Sep 2019 09:18:22 +0200 Subject: [PATCH 06/12] Fixed AdminDeathsRemoveCommand allowing to set a negative number of deaths Also fixed the "[total]" textvariable not working in its success message --- .../commands/admin/deaths/AdminDeathsRemoveCommand.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java index 884026da7..3e759773c 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/deaths/AdminDeathsRemoveCommand.java @@ -38,8 +38,12 @@ public class AdminDeathsRemoveCommand extends CompositeCommand { } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); } else { - getPlayers().setDeaths(getWorld(), target, getPlayers().getDeaths(getWorld(), target) - Integer.valueOf(args.get(1))); - user.sendMessage("commands.admin.deaths.remove.success", TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1)); + // Make sure it cannot go under 0. + int newDeaths = Math.max(getPlayers().getDeaths(getWorld(), target) - Integer.valueOf(args.get(1)), 0); + getPlayers().setDeaths(getWorld(), target, newDeaths); + user.sendMessage("commands.admin.deaths.remove.success", + TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1), + "[total]", String.valueOf(newDeaths)); return true; } From 6c3667e3edc482eece45e0254fcda12dc9efa6b9 Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sun, 29 Sep 2019 09:55:00 +0200 Subject: [PATCH 07/12] Improved success messages for AdminResetsSetCommand and AdminResetsResetCommand Also allowed AdminResetsSetCommand to set the resets to 0. --- .../api/commands/admin/resets/AdminResetsResetCommand.java | 4 ++-- .../api/commands/admin/resets/AdminResetsSetCommand.java | 7 ++++--- src/main/resources/locales/en-US.yml | 3 +++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsResetCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsResetCommand.java index 5ce82eb09..bfa631ab1 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsResetCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsResetCommand.java @@ -39,7 +39,7 @@ public class AdminResetsResetCommand extends ConfirmableCommand { getIWM().setResetEpoch(getWorld()); // Reset all current players Bukkit.getOnlinePlayers().stream().map(Player::getUniqueId).filter(getPlayers()::isKnown).forEach(u -> getPlayers().setResets(getWorld(), u, 0)); - user.sendMessage("general.success"); + user.sendMessage("commands.admin.resets.reset.success-everyone"); }); return true; } else { @@ -50,7 +50,7 @@ public class AdminResetsResetCommand extends ConfirmableCommand { return false; } else { getPlayers().setResets(getWorld(), target, 0); - user.sendMessage("general.success"); + user.sendMessage("commands.admin.resets.reset.success", TextVariables.NAME, args.get(0)); return true; } } diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsSetCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsSetCommand.java index ea989f6c2..449c38ee8 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsSetCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsSetCommand.java @@ -23,7 +23,7 @@ public class AdminResetsSetCommand extends CompositeCommand { @Override public boolean execute(User user, String label, List args) { - if (args.isEmpty() || args.size() != 2) { + if (args.size() != 2) { showHelp(this, user); return false; } @@ -31,11 +31,12 @@ public class AdminResetsSetCommand extends CompositeCommand { UUID target = getPlayers().getUUID(args.get(0)); if (target == null) { user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); - } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { + } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) <= 0) { user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); } else { getPlayers().setResets(getWorld(), target, Integer.valueOf(args.get(1))); - user.sendMessage("general.success"); + user.sendMessage("commands.admin.resets.set.success", + TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1)); return true; } diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 9078c89bb..795e9db42 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -54,9 +54,12 @@ commands: set: description: "sets the resets of this player" parameters: " " + success: "&aSuccessfully set &b[name]&a's resets to &b[number]&a." reset: description: "resets the resets of this player to 0" parameters: "" + success-everyone: "&aSuccessfully reset &beveryone&a's name resets to &b0&a." + success: "&aSuccessfully reset &b[name]&a's resets to &b0&a." purge: parameters: "[days]" description: "purge islands abandoned for more than [days]" From ac2f45ac8cf9504f5855497cc8b96da5638c6d6b Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sun, 29 Sep 2019 09:56:47 +0200 Subject: [PATCH 08/12] Fixed mistake in 'commands.admin.resets.reset.success-everyone' in en-US --- src/main/resources/locales/en-US.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 795e9db42..4424b7b1b 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -58,7 +58,7 @@ commands: reset: description: "resets the resets of this player to 0" parameters: "" - success-everyone: "&aSuccessfully reset &beveryone&a's name resets to &b0&a." + success-everyone: "&aSuccessfully reset &beveryone&a's resets to &b0&a." success: "&aSuccessfully reset &b[name]&a's resets to &b0&a." purge: parameters: "[days]" From a415a65e7e7364af901331a154e16e4d3188be9e Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sun, 29 Sep 2019 09:59:20 +0200 Subject: [PATCH 09/12] Added AdminResetsAddCommand and AdminResetsRemoveCommand --- .../admin/resets/AdminResetsAddCommand.java | 50 ++++++++++++++++++ .../admin/resets/AdminResetsCommand.java | 2 + .../resets/AdminResetsRemoveCommand.java | 52 +++++++++++++++++++ src/main/resources/locales/en-US.yml | 8 +++ 4 files changed, 112 insertions(+) create mode 100644 src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsAddCommand.java create mode 100644 src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsRemoveCommand.java diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsAddCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsAddCommand.java new file mode 100644 index 000000000..3884da0fb --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsAddCommand.java @@ -0,0 +1,50 @@ +package world.bentobox.bentobox.api.commands.admin.resets; + +import org.apache.commons.lang.math.NumberUtils; +import org.eclipse.jdt.annotation.NonNull; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; + +import java.util.List; +import java.util.UUID; + +/** + * @author Poslovitch + * @since 1.8.0 + */ +public class AdminResetsAddCommand extends CompositeCommand { + + public AdminResetsAddCommand(AdminResetsCommand parent) { + super(parent, "add"); + } + + @Override + public void setup() { + setDescription("commands.admin.resets.add.description"); + setParametersHelp("commands.admin.resets.add.parameters"); + } + + @Override + public boolean execute(User user, String label, @NonNull List args) { + if (args.size() != 2) { + showHelp(this, user); + return false; + } + + UUID target = getPlayers().getUUID(args.get(0)); + if (target == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); + } else { + getPlayers().setResets(getWorld(), target, getPlayers().getResets(getWorld(), target) + Integer.valueOf(args.get(1))); + user.sendMessage("commands.admin.resets.add.success", + TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1), + "[total]", String.valueOf(getPlayers().getResets(getWorld(), target))); + return true; + } + + return false; + } +} diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsCommand.java index 5e0e8d440..5776250ca 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsCommand.java @@ -18,6 +18,8 @@ public class AdminResetsCommand extends CompositeCommand { new AdminResetsSetCommand(this); new AdminResetsResetCommand(this); + new AdminResetsAddCommand(this); + new AdminResetsRemoveCommand(this); } @Override diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsRemoveCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsRemoveCommand.java new file mode 100644 index 000000000..24eb111d2 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/resets/AdminResetsRemoveCommand.java @@ -0,0 +1,52 @@ +package world.bentobox.bentobox.api.commands.admin.resets; + +import org.apache.commons.lang.math.NumberUtils; +import org.eclipse.jdt.annotation.NonNull; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; + +import java.util.List; +import java.util.UUID; + +/** + * @author Poslovitch + * @since 1.8.0 + */ +public class AdminResetsRemoveCommand extends CompositeCommand { + + public AdminResetsRemoveCommand(AdminResetsCommand parent) { + super(parent, "remove"); + } + + @Override + public void setup() { + setDescription("commands.admin.resets.remove.description"); + setParametersHelp("commands.admin.resets.remove.parameters"); + } + + @Override + public boolean execute(User user, String label, @NonNull List args) { + if (args.size() != 2) { + showHelp(this, user); + return false; + } + + UUID target = getPlayers().getUUID(args.get(0)); + if (target == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + } else if (!NumberUtils.isNumber(args.get(1)) || Integer.valueOf(args.get(1)) < 0) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); + } else { + // Make sure it cannot go under 0. + int newResets = Math.max(getPlayers().getResets(getWorld(), target) - Integer.valueOf(args.get(1)), 0); + getPlayers().setResets(getWorld(), target, newResets); + user.sendMessage("commands.admin.resets.remove.success", + TextVariables.NAME, args.get(0), TextVariables.NUMBER, args.get(1), + "[total]", String.valueOf(newResets)); + return true; + } + + return false; + } +} diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 4424b7b1b..7e6dca363 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -60,6 +60,14 @@ commands: parameters: "" success-everyone: "&aSuccessfully reset &beveryone&a's resets to &b0&a." success: "&aSuccessfully reset &b[name]&a's resets to &b0&a." + add: + description: "adds resets to the player" + parameters: " " + success: "&aSuccessfully added &b[number] &aresets to &b[name], increasing the total to &b[total]&a resets." + remove: + description: "removes resets to the player" + parameters: " " + success: "&aSuccessfully removed &b[number] &aresets to &b[name], decreasing the total to &b[total]&a resets." purge: parameters: "[days]" description: "purge islands abandoned for more than [days]" From 477f60ae033bc4f63528d78d62fa8335e6deafbc Mon Sep 17 00:00:00 2001 From: Florian CUNY Date: Sun, 29 Sep 2019 10:26:39 +0200 Subject: [PATCH 10/12] Added Banner patterns support in Blueprints Implements https://github.com/BentoBoxWorld/BentoBox/issues/961 --- .../blueprints/BlueprintClipboard.java | 7 ++++++ .../bentobox/blueprints/BlueprintPaster.java | 7 ++++++ .../dataobjects/BlueprintBlock.java | 22 +++++++++++++++++++ .../dataobjects/BlueprintEntity.java | 3 +++ 4 files changed, 39 insertions(+) diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java index 822a3cac9..36205c4e8 100644 --- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java +++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintClipboard.java @@ -14,6 +14,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Banner; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.CreatureSpawner; @@ -288,6 +289,12 @@ public class BlueprintClipboard { cs.setSpawnRange(spawner.getSpawnRange()); b.setCreatureSpawner(cs); } + + // Banners + if (blockState instanceof Banner) { + b.setBannerPatterns(((Banner) blockState).getPatterns()); + } + this.bpBlocks.put(pos, b); return true; } diff --git a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java index 8a3732fa6..792c2e225 100644 --- a/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java +++ b/src/main/java/world/bentobox/bentobox/blueprints/BlueprintPaster.java @@ -11,6 +11,7 @@ import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Banner; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -246,6 +247,12 @@ public class BlueprintPaster { spawner.setSpawnRange(s.getSpawnRange()); bs.update(true, false); } + // Banners + if (bs instanceof Banner) { + Banner banner = (Banner) bs; + banner.setPatterns(bpBlock.getBannerPatterns()); + banner.update(true, false); + } } /** diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBlock.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBlock.java index cacda5cf8..a54c38a0b 100644 --- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBlock.java +++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintBlock.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.bukkit.block.banner.Pattern; import org.bukkit.inventory.ItemStack; import com.google.gson.annotations.Expose; @@ -22,6 +23,11 @@ public class BlueprintBlock { private Map inventory; @Expose private BlueprintCreatureSpawner creatureSpawner; + /** + * @since 1.8.0 + */ + @Expose + private List bannerPatterns; public BlueprintBlock(String blockData) { this.blockData = blockData; @@ -82,4 +88,20 @@ public class BlueprintBlock { public void setCreatureSpawner(BlueprintCreatureSpawner creatureSpawner) { this.creatureSpawner = creatureSpawner; } + + /** + * @return list of the banner patterns + * @since 1.8.0 + */ + public List getBannerPatterns() { + return bannerPatterns; + } + + /** + * @param bannerPatterns the banner Patterns to set + * @since 1.8.0 + */ + public void setBannerPatterns(List bannerPatterns) { + this.bannerPatterns = bannerPatterns; + } } diff --git a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java index 3ee5dea54..e42cd2eb9 100644 --- a/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java +++ b/src/main/java/world/bentobox/bentobox/blueprints/dataobjects/BlueprintEntity.java @@ -41,6 +41,9 @@ public class BlueprintEntity { @Expose private Style style; + /** + * @since 1.8.0 + */ public void configureEntity(Entity e) { if (e instanceof Colorable) { ((Colorable) e).setColor(color); From 8a1d96910317a782187940489546bc227bbc7fb0 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 29 Sep 2019 14:35:15 -0700 Subject: [PATCH 11/12] Added ability to reset one island flag to default for all islands https://github.com/BentoBoxWorld/BentoBox/issues/958 --- .../admin/AdminResetFlagsCommand.java | 41 +++++- .../bentobox/managers/IslandsManager.java | 13 ++ .../bentobox/managers/island/IslandCache.java | 14 ++ src/main/resources/locales/en-US.yml | 3 + .../managers/island/IslandCacheTest.java | 136 ++++++++++++------ 5 files changed, 154 insertions(+), 53 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java index 37a0ad99f..fa0dbc1c2 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommand.java @@ -1,10 +1,17 @@ package world.bentobox.bentobox.api.commands.admin; import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.stream.Collectors; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.commands.ConfirmableCommand; +import world.bentobox.bentobox.api.flags.Flag; +import world.bentobox.bentobox.api.flags.Flag.Type; +import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.util.Util; /** * Admin command to reset all islands in a world to the default flag setting in the game mode config.yml @@ -13,25 +20,47 @@ import world.bentobox.bentobox.api.user.User; */ public class AdminResetFlagsCommand extends ConfirmableCommand { + private List options; + public AdminResetFlagsCommand(CompositeCommand parent) { super(parent, "resetflags"); + options = getPlugin().getFlagsManager().getFlags().stream() + .filter(f -> f.getType().equals(Type.PROTECTION) || f.getType().equals(Type.SETTING)) + .map(Flag::getID).collect(Collectors.toList()); } @Override public void setup() { setPermission("admin.resetflags"); setOnlyPlayer(false); + setParametersHelp("commands.admin.resetflags.parameters"); setDescription("commands.admin.resetflags.description"); } @Override public boolean execute(User user, String label, List args) { - // Everything's fine, we can set the island as spawn :) - askConfirmation(user, () -> { - getIslands().resetAllFlags(getWorld()); - user.sendMessage("commands.admin.resetflags.success"); - }); - return true; + if (args.isEmpty()) { + askConfirmation(user, user.getTranslation("commands.admin.resetflags.confirm"), () -> { + getIslands().resetAllFlags(getWorld()); + user.sendMessage("commands.admin.resetflags.success"); + }); + return true; + } else if (args.size() == 1 && options.contains(args.get(0).toUpperCase(Locale.ENGLISH))) { + getPlugin().getFlagsManager().getFlag(args.get(0).toUpperCase(Locale.ENGLISH)).ifPresent(flag -> + askConfirmation(user, user.getTranslation("commands.admin.resetflags.confirm"), () -> { + getIslands().resetFlag(getWorld(), flag); + user.sendMessage("commands.admin.resetflags.success-one", TextVariables.NAME, flag.getID()); + })); + return true; + } + // Show help + showHelp(this, user); + return false; } + @Override + public Optional> tabComplete(User user, String alias, List args) { + String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; + return Optional.of(Util.tabLimit(options, lastArg)); + } } diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java index 12d4cd80f..3c93a625a 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java @@ -38,6 +38,7 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.island.IslandEvent; import world.bentobox.bentobox.api.events.island.IslandEvent.Reason; +import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.logs.LogEntry; import world.bentobox.bentobox.api.user.User; @@ -1211,6 +1212,17 @@ public class IslandsManager { this.saveAll(); } + /** + * Resets a flag to gamemode config.yml default + * @param world - world + * @param flag - flag to reset + * @since 1.8.0 + */ + public void resetFlag(World world, Flag flag) { + islandCache.resetFlag(world, flag); + this.saveAll(); + } + /** * Returns whether the specified island custom name exists in this world. * @param world World of the gamemode @@ -1222,4 +1234,5 @@ public class IslandsManager { return getIslands(world).stream().filter(island -> island.getName() != null).map(Island::getName) .anyMatch(n -> ChatColor.stripColor(n).equals(ChatColor.stripColor(name))); } + } diff --git a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java index 75119f9bf..71296a2d5 100644 --- a/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java +++ b/src/main/java/world/bentobox/bentobox/managers/island/IslandCache.java @@ -16,6 +16,8 @@ import org.bukkit.World; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Util; @@ -312,4 +314,16 @@ public class IslandCache { World w = Util.getWorld(world); islandsById.values().stream().filter(i -> i.getWorld().equals(w)).forEach(Island::setFlagsDefaults); } + + /** + * Resets a specific flag on all game mode islands in world to default setting + * @param world - world + * @param flag - flag to reset + * @since 1.8.0 + */ + public void resetFlag(World world, Flag flag) { + World w = Util.getWorld(world); + int setting = BentoBox.getInstance().getIWM().getDefaultIslandFlags(w).getOrDefault(flag, flag.getDefaultRank()); + islandsById.values().stream().filter(i -> i.getWorld().equals(w)).forEach(i -> i.setFlag(flag, setting)); + } } diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 9078c89bb..093d6011a 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -310,8 +310,11 @@ commands: &aLeft click to increment &aRight click to decrement resetflags: + parameters: "[flag]" description: "Reset all islands to default flag settings in config.yml" + confirm: "&4This will reset the flag(s) to default for all islands!" success: "&aSuccessfully reset all islands' flags to the default settings." + success-one: "&a[name] flag set to default for all islands." world: description: "Manage world settings" delete: diff --git a/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java b/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java index 39f5c3bf6..51b3feec2 100644 --- a/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/island/IslandCacheTest.java @@ -2,14 +2,16 @@ package world.bentobox.bentobox.managers.island; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import java.util.Collections; import java.util.UUID; import org.bukkit.Location; @@ -17,15 +19,18 @@ import org.bukkit.World; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.bentobox.managers.IslandsManager; @@ -33,25 +38,37 @@ import world.bentobox.bentobox.managers.RanksManager; import world.bentobox.bentobox.util.Util; @RunWith(PowerMockRunner.class) -@PrepareForTest(Util.class) +@PrepareForTest({BentoBox.class, Util.class}) public class IslandCacheTest { + @Mock private BentoBox plugin; - private static World world; - + @Mock + private World world; + @Mock private Island island; + // UUID private UUID owner = UUID.randomUUID(); + @Mock private Location location; + // Test class + private IslandCache ic; + @Mock + private IslandWorldManager iwm; + @Mock + private Flag flag; + @Mock + private IslandsManager im; @Before public void setUp() throws Exception { - plugin = mock(BentoBox.class); - - world = mock(World.class); + // Plugin + Whitebox.setInternalState(BentoBox.class, "instance", plugin); // Worlds - IslandWorldManager iwm = mock(IslandWorldManager.class); when(plugin.getIWM()).thenReturn(iwm); + // IWM + when(iwm.getDefaultIslandFlags(any())).thenReturn(Collections.singletonMap(flag, 400)); when(iwm.inWorld(any(World.class))).thenReturn(true); when(iwm.inWorld(any(Location.class))).thenReturn(true); @@ -59,14 +76,11 @@ public class IslandCacheTest { when(Util.getWorld(Mockito.any())).thenReturn(world); // Mock up IslandsManager - IslandsManager im = mock(IslandsManager.class); when(plugin.getIslands()).thenReturn(im); - - - island = mock(Island.class); + // Island when(island.getWorld()).thenReturn(world); - location = mock(Location.class); + // Location when(location.getWorld()).thenReturn(world); when(location.getBlockX()).thenReturn(0); when(location.getBlockY()).thenReturn(0); @@ -82,25 +96,26 @@ public class IslandCacheTest { when(island.getMinX()).thenReturn(-200); when(island.getMinZ()).thenReturn(-200); + // New cache + ic = new IslandCache(); } - @Test - public void testIslandCache() { - assertNotNull(new IslandCache()); - } - + /** + * Test for {@link IslandCache#addIsland(Island)} + */ @Test public void testAddIsland() { - IslandCache ic = new IslandCache(); assertTrue(ic.addIsland(island)); // Check if they are added assertEquals(island, ic.get(world, owner)); assertEquals(island, ic.get(location)); } + /** + * Test for {@link IslandCache#addPlayer(UUID, Island)} + */ @Test public void testAddPlayer() { - IslandCache ic = new IslandCache(); UUID playerUUID = UUID.randomUUID(); ic.addPlayer(playerUUID, island); // Check if they are added @@ -109,9 +124,11 @@ public class IslandCacheTest { } + /** + * Test for {@link IslandCache#clear()} + */ @Test public void testClear() { - IslandCache ic = new IslandCache(); ic.addIsland(island); // Check if they are added assertEquals(island, ic.get(world, owner)); @@ -121,10 +138,11 @@ public class IslandCacheTest { assertNull(ic.get(location)); } + /** + * Test for {@link IslandCache#deleteIslandFromCache(Island)} + */ @Test public void testDeleteIslandFromCache() { - - IslandCache ic = new IslandCache(); ic.addIsland(island); // Check if they are added assertEquals(island, ic.get(world, owner)); @@ -156,31 +174,35 @@ public class IslandCacheTest { } + /** + * Test for {@link IslandCache#get(Location)} + */ @Test public void testGetLocation() { - IslandCache ic = new IslandCache(); ic.addIsland(island); // Check if they are added assertEquals(island, ic.get(location)); - } + /** + * Test for {@link IslandCache#get(World, UUID)} + */ @Test public void testGetUUID() { - IslandCache ic = new IslandCache(); ic.addIsland(island); // Check if they are added assertEquals(island, ic.get(world, owner)); } + /** + * Test for {@link IslandCache#getIslandAt(Location)} + */ @Test public void testGetIslandAtLocation() { // Set coords to be in island space when(island.inIslandSpace(Mockito.any(Integer.class), Mockito.any(Integer.class))).thenReturn(true); // Set plugin Util.setPlugin(plugin); - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); // Check exact match for location @@ -199,16 +221,11 @@ public class IslandCacheTest { assertNull(ic.getIslandAt(location2)); } - /* - @Test - public void testGetIslands() { - fail("Not yet implemented"); // TODO - } + /** + * Test for {@link IslandCache#getMembers(World, UUID, int)} */ @Test public void testGetMembers() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); assertTrue(ic.getMembers(world, null, RanksManager.MEMBER_RANK).isEmpty()); @@ -217,10 +234,12 @@ public class IslandCacheTest { assertEquals(3, ic.getMembers(world, island.getOwner(), RanksManager.MEMBER_RANK).size()); } + + /** + * Test for {@link IslandCache#getOwner(World, UUID)} + */ @Test public void testGetOwner() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); assertEquals(owner, ic.getOwner(world, owner)); @@ -228,10 +247,11 @@ public class IslandCacheTest { assertNull(ic.getOwner(world, UUID.randomUUID())); } + /** + * Test for {@link IslandCache#hasIsland(World, UUID)} + */ @Test public void testHasIsland() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); assertTrue(ic.hasIsland(world, owner)); @@ -239,12 +259,12 @@ public class IslandCacheTest { assertFalse(ic.hasIsland(world, null)); } + /** + * Test for {@link IslandCache#removePlayer(World, UUID)} + */ @Test public void testRemovePlayer() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); - assertTrue(ic.hasIsland(world, owner)); ic.removePlayer(world, null); assertTrue(ic.hasIsland(world, owner)); @@ -254,18 +274,20 @@ public class IslandCacheTest { assertFalse(ic.hasIsland(world, owner)); } + /** + * Test for {@link IslandCache#size()} + */ @Test public void testSize() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); assertEquals(1, ic.size()); } + /** + * Test for {@link IslandCache#setOwner(Island, UUID)} + */ @Test public void testSetOwner() { - // New cache - IslandCache ic = new IslandCache(); ic.addIsland(island); UUID newOwnerUUID = UUID.randomUUID(); ic.setOwner(island, newOwnerUUID); @@ -274,4 +296,24 @@ public class IslandCacheTest { assertEquals(island, ic.get(world, newOwnerUUID)); assertEquals(island, ic.get(island.getCenter())); } + + /** + * Test for {@link IslandCache#resetFlag(World, world.bentobox.bentobox.api.flags.Flag)} + */ + @Test + public void testResetFlag() { + ic.addIsland(island); + ic.resetFlag(world, flag); + verify(island).setFlag(eq(flag), eq(400)); + } + + /** + * Test for {@link IslandCache#resetAllFlags(World)} + */ + @Test + public void testResetAllFlags() { + ic.addIsland(island); + ic.resetAllFlags(world); + verify(island).setFlagsDefaults(); + } } From 4d861613e90e1f1bf64fd4d6a78dd42c85f982b6 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 29 Sep 2019 14:35:30 -0700 Subject: [PATCH 12/12] Added test class for AdminResetFlagsCommand --- .../admin/AdminResetFlagsCommandTest.java | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java diff --git a/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java new file mode 100644 index 000000000..56bda618e --- /dev/null +++ b/src/test/java/world/bentobox/bentobox/api/commands/admin/AdminResetFlagsCommandTest.java @@ -0,0 +1,227 @@ +package world.bentobox.bentobox.api.commands.admin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitScheduler; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.Settings; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.flags.Flag; +import world.bentobox.bentobox.api.flags.Flag.Type; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.managers.CommandsManager; +import world.bentobox.bentobox.managers.FlagsManager; +import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.managers.PlaceholdersManager; +import world.bentobox.bentobox.managers.PlayersManager; + +/** + * @author tastybento + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({Bukkit.class, BentoBox.class, User.class }) +public class AdminResetFlagsCommandTest { + + @Mock + private CompositeCommand ac; + private UUID uuid = UUID.randomUUID(); + @Mock + private IslandsManager im; + @Mock + private PlayersManager pm; + @Mock + private FlagsManager fm; + @Mock + private Flag flag; + @Mock + private Flag flag2; + @Mock + private Flag flag3; + @Mock + private Player player; + + private AdminResetFlagsCommand arf; + private @Nullable User user; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + // Set up plugin + BentoBox plugin = mock(BentoBox.class); + Whitebox.setInternalState(BentoBox.class, "instance", plugin); + + // Command manager + CommandsManager cm = mock(CommandsManager.class); + when(plugin.getCommandsManager()).thenReturn(cm); + + // Parent command has no aliases + ac = mock(CompositeCommand.class); + when(ac.getSubCommandAliases()).thenReturn(new HashMap<>()); + when(ac.getPermissionPrefix()).thenReturn("bskyblock."); + + // Player + when(player.getUniqueId()).thenReturn(uuid); + user = User.getInstance(player); + + // Flags manager + when(plugin.getFlagsManager()).thenReturn(fm); + when(flag.getType()).thenReturn(Type.PROTECTION); + when(flag2.getType()).thenReturn(Type.SETTING); + when(flag3.getType()).thenReturn(Type.WORLD_SETTING); + when(flag.getID()).thenReturn("FLAG1"); + when(flag2.getID()).thenReturn("FLAG2"); + when(flag3.getID()).thenReturn("FLAG3"); + @NonNull + List list = new ArrayList<>(); + list.add(flag); + list.add(flag2); + list.add(flag3); + when(fm.getFlags()).thenReturn(list); + + // Locales & Placeholders + LocalesManager lm = mock(LocalesManager.class); + when(lm.get(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class)); + PlaceholdersManager phm = mock(PlaceholdersManager.class); + when(plugin.getPlaceholdersManager()).thenReturn(phm); + when(phm.replacePlaceholders(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class)); + + when(plugin.getLocalesManager()).thenReturn(lm); + + // Confirmation + Settings settings = mock(Settings.class); + when(settings.getConfirmationTime()).thenReturn(10); + when(plugin.getSettings()).thenReturn(settings); + + // Server & Scheduler + BukkitScheduler sch = mock(BukkitScheduler.class); + PowerMockito.mockStatic(Bukkit.class); + when(Bukkit.getScheduler()).thenReturn(sch); + + + // Class + arf = new AdminResetFlagsCommand(ac); + + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + User.clearUsers(); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#AdminResetFlagsCommand(world.bentobox.bentobox.api.commands.CompositeCommand)}. + */ + @Test + public void testAdminResetFlagsCommand() { + assertEquals("resetflags", arf.getLabel()); + verify(flag).getID(); + verify(flag2).getID(); + verify(flag3, never()).getID(); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#setup()}. + */ + @Test + public void testSetup() { + assertFalse(arf.isOnlyPlayer()); + assertEquals("bskyblock.admin.resetflags", arf.getPermission()); + assertEquals("commands.admin.resetflags.parameters", arf.getParameters()); + assertEquals("commands.admin.resetflags.description", arf.getDescription()); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringTwoArgs() { + List args = Arrays.asList("sdfsd", "werwerw"); + assertFalse(arf.execute(user, "", args)); + verify(player).sendMessage(eq("commands.help.header")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringOneArgNotFlag() { + assertFalse(arf.execute(user, "", Collections.singletonList("FLAG3"))); + verify(player).sendMessage(eq("commands.help.header")); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringOneArgFlag2() { + assertTrue(arf.execute(user, "", Collections.singletonList("FLAG2"))); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringOneArgFlag1() { + assertTrue(arf.execute(user, "", Collections.singletonList("FLAG1"))); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfString() { + assertTrue(arf.execute(user, "", Collections.emptyList())); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.admin.AdminResetFlagsCommand#tabComplete(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testTabCompleteUserStringListOfString() { + Optional> list = arf.tabComplete(user, "", Collections.emptyList()); + assertTrue(list.isPresent()); + assertTrue(list.get().size() == 2); + assertTrue(list.get().contains("FLAG1")); + assertTrue(list.get().contains("FLAG2")); + assertFalse(list.get().contains("FLAG3")); + } + +}