diff --git a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java index 367eee1..71171ad 100644 --- a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java +++ b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java @@ -13,8 +13,11 @@ import net.knarcraft.paidsigns.command.RemoveTabCommand; import net.knarcraft.paidsigns.listener.SignListener; import net.knarcraft.paidsigns.manager.EconomyManager; import net.knarcraft.paidsigns.manager.PaidSignManager; +import net.knarcraft.paidsigns.manager.TrackedSignManager; import net.milkbowl.vault.economy.Economy; +import org.bukkit.command.CommandExecutor; import org.bukkit.command.PluginCommand; +import org.bukkit.command.TabCompleter; import org.bukkit.command.TabExecutor; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.PluginManager; @@ -31,6 +34,8 @@ public final class PaidSigns extends JavaPlugin { private PaidSignManager signManager; private boolean ignoreCase; private boolean ignoreColor; + private boolean enableRefunds; + private int refundPercentage; /** * Instantiates a new paid signs object @@ -53,6 +58,7 @@ public final class PaidSigns extends JavaPlugin { public void onEnable() { setupVault(); signManager = new PaidSignManager(PaidSignManager.loadSigns()); + TrackedSignManager.loadTrackedSigns(); loadConfig(); PluginManager pluginManager = getServer().getPluginManager(); @@ -72,6 +78,7 @@ public final class PaidSigns extends JavaPlugin { this.reloadConfig(); loadConfig(); signManager = new PaidSignManager(PaidSignManager.loadSigns()); + TrackedSignManager.loadTrackedSigns(); } /** @@ -101,46 +108,56 @@ public final class PaidSigns extends JavaPlugin { return this.ignoreColor; } + /** + * Checks whether refunds are currently enabled + * + * @return
Whether refunds are currently enabled
+ */ + public boolean areRefundsEnabled() { + return this.enableRefunds; + } + + /** + * Gets the percentage of the initial cost to refund the sign creator + * + * @returnThe percentage of the cost to refund
+ */ + public int getRefundPercentage() { + if (this.refundPercentage < 0) { + return 0; + } else if (refundPercentage > 100) { + return 100; + } + return this.refundPercentage; + } + /** * Registers the commands used by this plugin */ private void registerCommands() { - PluginCommand addCommand = this.getCommand("addPaidSign"); - if (addCommand != null) { - addCommand.setExecutor(new AddCommand()); - addCommand.setTabCompleter(new AddTabCompleter()); - } + registerCommand("addPaidSign", new AddCommand(), new AddTabCompleter()); + registerCommand("listPaidSigns", new ListCommand(), new ListTabCompleter()); + registerCommand("addPaidSignCondition", new AddConditionCommand(), new AddConditionTabCompleter()); + registerCommand("removePaidSignCondition", new RemoveConditionCommand(), new RemoveConditionTabCompleter()); - PluginCommand listCommand = this.getCommand("listPaidSigns"); - if (listCommand != null) { - listCommand.setExecutor(new ListCommand()); - listCommand.setTabCompleter(new ListTabCompleter()); - } + TabExecutor removeTabExecutor = new RemoveTabCommand(); + registerCommand("removePaidSign", removeTabExecutor, removeTabExecutor); + TabExecutor reloadTabExecutor = new ReloadTabCommand(); + registerCommand("reload", reloadTabExecutor, reloadTabExecutor); + } - PluginCommand addConditionCommand = this.getCommand("addPaidSignCondition"); - if (addConditionCommand != null) { - addConditionCommand.setExecutor(new AddConditionCommand()); - addConditionCommand.setTabCompleter(new AddConditionTabCompleter()); - } - - PluginCommand removeConditionCommand = this.getCommand("removePaidSignCondition"); - if (removeConditionCommand != null) { - removeConditionCommand.setExecutor(new RemoveConditionCommand()); - removeConditionCommand.setTabCompleter(new RemoveConditionTabCompleter()); - } - - PluginCommand removeCommand = this.getCommand("removePaidSign"); - if (removeCommand != null) { - TabExecutor removeTabExecutor = new RemoveTabCommand(); - removeCommand.setExecutor(removeTabExecutor); - removeCommand.setTabCompleter(removeTabExecutor); - } - - PluginCommand reloadCommand = this.getCommand("reload"); - if (reloadCommand != null) { - TabExecutor reloadTabExecutor = new ReloadTabCommand(); - reloadCommand.setExecutor(reloadTabExecutor); - reloadCommand.setTabCompleter(reloadTabExecutor); + /** + * Registers a command if possible + * + * @param commandThe command to register
+ * @param commandExecutorThe command executor for executing the command
+ * @param tabCompleterThe tab completer for tab-completing the command
+ */ + private void registerCommand(String command, CommandExecutor commandExecutor, TabCompleter tabCompleter) { + PluginCommand pluginCommand = this.getCommand(command); + if (pluginCommand != null) { + pluginCommand.setExecutor(commandExecutor); + pluginCommand.setTabCompleter(tabCompleter); } } @@ -153,6 +170,8 @@ public final class PaidSigns extends JavaPlugin { this.saveDefaultConfig(); ignoreCase = config.getBoolean("ignoreCase", true); ignoreColor = config.getBoolean("ignoreColor", false); + enableRefunds = config.getBoolean("enableRefunds", true); + refundPercentage = config.getInt("refundPercentage", 100); } /** diff --git a/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java b/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java new file mode 100644 index 0000000..a050ea7 --- /dev/null +++ b/src/main/java/net/knarcraft/paidsigns/container/TrackedSign.java @@ -0,0 +1,42 @@ +package net.knarcraft.paidsigns.container; + +import java.util.UUID; + +/** + * A representation of a sign placed by a player that matched a paid sign + */ +public class TrackedSign { + + private final UUID playerId; + private final double cost; + + /** + * Instantiates a new tracked sign + * + * @param playerIdThe unique id of the player that created the sign
+ * @param costThe cost the player paid for creating the sign
+ */ + public TrackedSign(UUID playerId, double cost) { + this.playerId = playerId; + this.cost = cost; + } + + /** + * Gets the id of the player that created this tracked sign + * + * @returnThe player that created this tracked sign
+ */ + public UUID getPlayerId() { + return this.playerId; + } + + /** + * Gets the cost the player paid for creating this paid sign + * + * @returnThe cost paid for creating this sign
+ */ + public double getCost() { + return this.cost; + } + +} diff --git a/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java b/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java new file mode 100644 index 0000000..c7c5eed --- /dev/null +++ b/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java @@ -0,0 +1,35 @@ +package net.knarcraft.paidsigns.listener; + +import net.knarcraft.paidsigns.PaidSigns; +import net.knarcraft.paidsigns.manager.TrackedSignManager; +import org.bukkit.block.Sign; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; + +import java.io.IOException; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A listener that listens for any tracked signs being broken + */ +public class BlockBreakListener implements Listener { + + @EventHandler(priority = EventPriority.MONITOR) + public void onBlockBreak(BlockBreakEvent event) { + if (event.getBlock().getState() instanceof Sign) { + try { + TrackedSignManager.removeTrackedSign(event.getBlock().getLocation()); + } catch (IOException e) { + e.printStackTrace(); + Logger logger = PaidSigns.getInstance().getLogger(); + logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); + logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); + } + } + } + +} diff --git a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java index ceed610..0ae4c03 100644 --- a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java +++ b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java @@ -3,13 +3,18 @@ package net.knarcraft.paidsigns.listener; import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.container.PaidSign; import net.knarcraft.paidsigns.manager.EconomyManager; +import net.knarcraft.paidsigns.manager.TrackedSignManager; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.SignChangeEvent; +import java.io.IOException; +import java.util.Arrays; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; /** * A listener for listening to registered paid signs @@ -50,19 +55,38 @@ public class SignListener implements Listener { return true; } - double cost = paidSign.getCost(); - boolean canAfford = EconomyManager.canAfford(player, cost); - if (!canAfford) { - player.sendMessage("[PaidSigns] You cannot afford to create this sign"); - event.setCancelled(true); - } else { - String unit = EconomyManager.getCurrency(cost != 1); - player.sendMessage(String.format("[PaidSigns] You paid %.2f %s to create the sign", cost, unit)); - EconomyManager.withdraw(player, cost); - } + performPaidSignTransaction(paidSign, player, event); return true; } return false; } + /** + * Performs the transaction to pay for the paid sign + * + * @param paidSignThe paid sign a match has been found for
+ * @param playerThe player that created the sign
+ * @param eventThe sign change event that caused the sign to be created
+ */ + private void performPaidSignTransaction(PaidSign paidSign, Player player, SignChangeEvent event) { + double cost = paidSign.getCost(); + boolean canAfford = EconomyManager.canAfford(player, cost); + if (!canAfford) { + player.sendMessage("[PaidSigns] You cannot afford to create this sign"); + event.setCancelled(true); + } else { + String unit = EconomyManager.getCurrency(cost != 1); + player.sendMessage(String.format("[PaidSigns] You paid %.2f %s to create the sign", cost, unit)); + EconomyManager.withdraw(player, cost); + try { + TrackedSignManager.addTrackedSign(event.getBlock().getLocation(), player.getUniqueId(), cost); + } catch (IOException e) { + e.printStackTrace(); + Logger logger = PaidSigns.getInstance().getLogger(); + logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); + logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); + } + } + } + } diff --git a/src/main/java/net/knarcraft/paidsigns/manager/EconomyManager.java b/src/main/java/net/knarcraft/paidsigns/manager/EconomyManager.java index b92e865..183340e 100644 --- a/src/main/java/net/knarcraft/paidsigns/manager/EconomyManager.java +++ b/src/main/java/net/knarcraft/paidsigns/manager/EconomyManager.java @@ -2,7 +2,6 @@ package net.knarcraft.paidsigns.manager; import net.milkbowl.vault.economy.Economy; import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; /** * A manager that performs all Economy tasks @@ -55,7 +54,7 @@ public final class EconomyManager { * @param playerThe player to withdraw money from
* @param costThe amount of money to withdraw
*/ - public static void withdraw(Player player, double cost) { + public static void withdraw(OfflinePlayer player, double cost) { economy.withdrawPlayer(player, cost); } diff --git a/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java new file mode 100644 index 0000000..807b3aa --- /dev/null +++ b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java @@ -0,0 +1,128 @@ +package net.knarcraft.paidsigns.manager; + +import net.knarcraft.paidsigns.PaidSigns; +import net.knarcraft.paidsigns.container.TrackedSign; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.logging.Level; + +/** + * A manager for keeping track of plugin-signs created by players + */ +public class TrackedSignManager { + + private static MapThe location the sign was created at
+ * @param playerIdThe unique id of the player that created the sign
+ * @throws IOExceptionIf unable to save the tracked signs
+ */ + public static void addTrackedSign(Location signLocation, UUID playerId, double cost) throws IOException { + trackedSigns.put(signLocation, new TrackedSign(playerId, cost)); + saveTrackedSigns(); + } + + /** + * Removes a tracked sign from the manager + * + * @param signLocationThe location the sign was removed from
+ * @throws IOExceptionIf unable to save the tracked signs
+ */ + public static void removeTrackedSign(Location signLocation) throws IOException { + if (!trackedSigns.containsKey(signLocation)) { + return; + } + trackedSigns.remove(signLocation); + saveTrackedSigns(); + if (!PaidSigns.getInstance().areRefundsEnabled()) { + return; + } + TrackedSign trackedSign = trackedSigns.get(signLocation); + OfflinePlayer player = Bukkit.getOfflinePlayer(trackedSign.getPlayerId()); + double refundSum = trackedSign.getCost() / 100 * PaidSigns.getInstance().getRefundPercentage(); + EconomyManager.withdraw(player, refundSum); + } + + /** + * Loads all tracked signs from the data file + */ + public static void loadTrackedSigns() { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile); + ConfigurationSection signSection = configuration.getConfigurationSection("trackedSigns"); + trackedSigns = new HashMap<>(); + + if (signSection == null) { + PaidSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in data.yml"); + return; + } + + for (String key : signSection.getKeys(false)) { + try { + loadSign(signSection, key); + } catch (InvalidConfigurationException e) { + PaidSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to load sign " + key + ": " + + e.getMessage()); + } + } + } + + /** + * Loads a sign from the save file + * + * @param signSectionThe configuration section containing signs
+ * @param keyThe sign key which is also the sign's location
+ * @throws InvalidConfigurationExceptionIf unable to load the sign
+ */ + private static void loadSign(ConfigurationSection signSection, String key) throws InvalidConfigurationException { + String[] locationParts = key.split(","); + Location signLocation; + try { + signLocation = new Location(Bukkit.getWorld(UUID.fromString(locationParts[0])), + Double.parseDouble(locationParts[1]), Double.parseDouble(locationParts[2]), + Double.parseDouble(locationParts[3])); + } catch (NumberFormatException exception) { + throw new InvalidConfigurationException("Invalid sign coordinates"); + } + + double cost = signSection.getDouble(key + ".cost"); + UUID playerId = UUID.fromString(Objects.requireNonNull(signSection.getString(key + ".playerId"))); + + TrackedSign trackedSign = new TrackedSign(playerId, cost); + trackedSigns.put(signLocation, trackedSign); + } + + /** + * Saves the managed tracked signs to the data file + * + * @throws IOExceptionIf unable to write to the data file
+ */ + private static void saveTrackedSigns() throws IOException { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile); + ConfigurationSection signSection = configuration.createSection("trackedSigns"); + + for (Location signLocation : trackedSigns.keySet()) { + TrackedSign sign = trackedSigns.get(signLocation); + String locationString = Objects.requireNonNull(signLocation.getWorld()).getUID() + "," + + signLocation.getBlockX() + "," + signLocation.getBlockY() + "," + signLocation.getBlockZ(); + signSection.set(locationString + ".cost", sign.getCost()); + signSection.set(locationString + ".playerId", sign.getPlayerId()); + } + configuration.save(signsFile); + } + +} diff --git a/src/main/java/net/knarcraft/paidsigns/utility/TabCompleteHelper.java b/src/main/java/net/knarcraft/paidsigns/utility/TabCompleteHelper.java index d0a5031..d2277d8 100644 --- a/src/main/java/net/knarcraft/paidsigns/utility/TabCompleteHelper.java +++ b/src/main/java/net/knarcraft/paidsigns/utility/TabCompleteHelper.java @@ -15,23 +15,6 @@ public final class TabCompleteHelper { } - /** - * Finds tab complete values that contain the typed text - * - * @param valuesThe values to filter
- * @param typedTextThe text the player has started typing
- * @returnThe given string values that contain the player's typed text
- */ - public static List