Compare commits
45 Commits
0.1.0-ALPH
...
0.6.0-ALPH
Author | SHA1 | Date | |
---|---|---|---|
b1aefdd9d9 | |||
c44ff5c890 | |||
c6d3a771c3 | |||
3e31c8c648 | |||
9c6921b4cd | |||
3b5218cb98 | |||
a1c9624fe1 | |||
a7d1da7f8a | |||
c2ffe5e903 | |||
3d83458b9c | |||
abb080b065 | |||
9bb234169d | |||
664115b2b4 | |||
4602ca71db | |||
30bca7b8f1 | |||
81e62eb664 | |||
5cbde82fff | |||
eb0e06f193 | |||
483ffaec2b | |||
797020aa7f | |||
15426a46f3 | |||
a1b1a5d112 | |||
996d062674 | |||
990339499a | |||
3b7268d2ff | |||
91d477b45a | |||
0f958f0908 | |||
36678fd2d0 | |||
4e44909f80 | |||
0ad953cc14 | |||
db869c0c5b | |||
8a030276c5 | |||
7e01d77723 | |||
86cb1c0fed | |||
5bc62d5bc0 | |||
2f559ce2af | |||
90b5ff7304 | |||
d76d5cdf93 | |||
6f35da03e7 | |||
eaa4f929ca | |||
419a79bc9f | |||
16faa1ddb2 | |||
d2f152334f | |||
4189053ed8 | |||
5e52e3d4de |
97
README.md
97
README.md
@ -3,10 +3,105 @@
|
||||
The paid-signs plugin is a plugin that lets you add costs for creating plugin signs. This allows restricting usage of
|
||||
signs such as CraftBook's gate/lift and other signs while still allowing every player to use the signs.
|
||||
|
||||
Note: OP players, and players with the '*' permission will have the `paidsigns.paymentexempt` permission and will not
|
||||
see any payment messages. For testing, you'll need to un-set the `paidsigns.paymentexempt` permission.
|
||||
|
||||
## Limitations
|
||||
|
||||
As this plugin only listens to sign change events, there are some limitations:
|
||||
|
||||
1. The plugin is not aware of whether the creation of a sign is successful
|
||||
2. It is assumed that any protection plugins run before this plugin, but it's not guaranteed
|
||||
3. Plugins changing the lines on signs when successful might create confusion and mismatches
|
||||
3. Plugins changing the lines on signs when successful might create confusion and mismatches
|
||||
|
||||
## Commands
|
||||
|
||||
* /addpaidsign <name> <cost> \[permission] \[ignore case] \[ignore color] \[match any condition]
|
||||
* /addpaidsigncondition <name (of a paid sign)> <line number> <string to match> \[executeRegEx] \[ignoreCase]
|
||||
\[ignoreColor]
|
||||
* /listpaidsigns \[name (of a paid sign)] \[line number]
|
||||
* /editpaidsign <sign name> <property>/<line number> \[new value]/<property> \[new value]
|
||||
* /removepaidsigncondition <name (of a paid sign)> <line number>
|
||||
* /removepaidsign <name (of a paid sign)>
|
||||
* /reload
|
||||
|
||||
## Command explanation
|
||||
|
||||
### /addpaidsign
|
||||
|
||||
This command adds a new paid sign that does nothing until a condition is added.
|
||||
|
||||
* name - A recognizable name only used to differentiate between registered paid signs
|
||||
* cost - The cost a player need to pay to create any sign matching the paid sign
|
||||
* permission - If the paid sign is used to represent a plugin sign, the permission should be the permission necessary
|
||||
for creating the plugin sign. This is used to decide if the plugin sign was created, or the player was denied.
|
||||
* ignore case - Whether any conditions of the paid sign should ignore case by default, when matching against text (
|
||||
default uses the config file value).
|
||||
* ignore color - Whether any condition of the paid sign should ignore color by default, when matching against text (
|
||||
default uses the config file value).
|
||||
* match any condition - Whether to trigger a paid sign match if a single one of the sign's conditions is true. This is
|
||||
mainly useful if several lines may contain the match string, or if trying to match a word.
|
||||
|
||||
### /addpaidsigncondition
|
||||
|
||||
This adds a condition to a paid sign which is used to decide if a sign created by a player matches the paid sign. Adding
|
||||
a paid sign condition to a line that already has one will replace the previous condition.
|
||||
|
||||
* name - The name of the paid sign to add the condition to
|
||||
* line number - The line on the sign (1-4) to search for any matches
|
||||
* string to match - The string or regular expression to look for on a sign
|
||||
* executeRegEx - Whether to use a regular expression match instead of looking for the exact string
|
||||
* ignoreCase - Whether this condition should ignore case when trying to match the string (default uses the "parent"
|
||||
sign's value)
|
||||
* ignoreColor - Whether this condition should ignore color when trying to match the string (default uses the "parent"
|
||||
sign's value)
|
||||
|
||||
### /listpaidsigns
|
||||
|
||||
This lists registered paid signs and paid sign conditions. No arguments will print a list of paid signs
|
||||
|
||||
* name - The name of the paid sign to see information about
|
||||
* line number - The line number of the condition to see information about
|
||||
|
||||
### /editpaidsign
|
||||
|
||||
* name - The name of the paid sign to edit
|
||||
* property/line number - The property to edit for the sign, or the line of the condition to edit
|
||||
* new value/property - The new property value if a property was specified in the second argument, or a condition
|
||||
property if a line number was specified in the second argument
|
||||
* new value - The new property value of the condition property specified in the third argument
|
||||
|
||||
### /removepaidsigncondition
|
||||
|
||||
Removes a paid sign condition from a sign
|
||||
|
||||
* name - The name of the paid sign to remove the condition from
|
||||
* line number - The line the condition is associated with
|
||||
|
||||
### /removepaidsign
|
||||
|
||||
Removes a registered paid sign
|
||||
|
||||
* name - The name of the paid sign to remove
|
||||
|
||||
## Permissions
|
||||
|
||||
* paidsigns.* - Grants all paid signs permissions
|
||||
* paidsigns.manage - Grants the permission to add/remove a paid sign
|
||||
* paidsigns.reload - Grants the permissions to reload the plugin
|
||||
* paidsigns.paymentexempt - Makes this player exempt from the cost of paid signs
|
||||
|
||||
## Configuration options
|
||||
|
||||
* language - The language to use for all messages displayed to players
|
||||
* ignoreCase - Whether to ignore the case (lowercase/uppercase) of the paid sign text. The option can be set on a
|
||||
per-sign basis, but this value is used if not specified. The correct value depends on whether the plugin signs it
|
||||
should match are case-sensitive or not.
|
||||
* ignoreColor - Whether to ignore any color or formatting applied to the text when trying to match a paid sign's text.
|
||||
The option can be set on a per-sign basis, but this value is used if not specified. The correct value depends on
|
||||
whether the plugin signs it should match allow coloring or not.
|
||||
* refundsEnabled - Whether to enable refunds to the sign creator when a sign detected as a paid sign is broken (payment
|
||||
will always go to the original creator)
|
||||
* refundPercentage - The percentage of the paid sign cost to refund (0-100)
|
||||
* refundAlways - Whether to refund when signs that players have paid for are broken by anything. This includes tnt,
|
||||
creepers, pistons and similar
|
8
pom.xml
8
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>net.knarcraft</groupId>
|
||||
<artifactId>paidsigns</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.6.0-ALPHA</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Paid Signs</name>
|
||||
@ -25,8 +25,8 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>16</source>
|
||||
<target>16</target>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@ -85,7 +85,7 @@
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>22.0.0</version>
|
||||
<version>23.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -1,15 +1,27 @@
|
||||
package net.knarcraft.paidsigns;
|
||||
|
||||
import net.knarcraft.paidsigns.command.AddCommand;
|
||||
import net.knarcraft.paidsigns.command.AddConditionCommand;
|
||||
import net.knarcraft.paidsigns.command.AddConditionTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.AddTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.EditCommand;
|
||||
import net.knarcraft.paidsigns.command.EditTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.ListCommand;
|
||||
import net.knarcraft.paidsigns.command.ListTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.ReloadTabCommand;
|
||||
import net.knarcraft.paidsigns.command.RemoveCommand;
|
||||
import net.knarcraft.paidsigns.command.RemoveTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.RemoveConditionCommand;
|
||||
import net.knarcraft.paidsigns.command.RemoveConditionTabCompleter;
|
||||
import net.knarcraft.paidsigns.command.RemoveTabCommand;
|
||||
import net.knarcraft.paidsigns.formatting.Translator;
|
||||
import net.knarcraft.paidsigns.listener.SignBreakListener;
|
||||
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;
|
||||
@ -24,8 +36,12 @@ public final class PaidSigns extends JavaPlugin {
|
||||
|
||||
private static PaidSigns paidSigns;
|
||||
private PaidSignManager signManager;
|
||||
private String language;
|
||||
private boolean ignoreCase;
|
||||
private boolean ignoreColor;
|
||||
private boolean refundsEnabled;
|
||||
private short refundPercentage;
|
||||
private boolean refundAlways;
|
||||
|
||||
/**
|
||||
* Instantiates a new paid signs object
|
||||
@ -47,11 +63,14 @@ public final class PaidSigns extends JavaPlugin {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
setupVault();
|
||||
signManager = new PaidSignManager(PaidSignManager.loadSigns());
|
||||
loadConfig();
|
||||
Translator.loadLanguages(language);
|
||||
signManager = new PaidSignManager(PaidSignManager.loadSigns());
|
||||
TrackedSignManager.loadTrackedSigns();
|
||||
|
||||
PluginManager pluginManager = getServer().getPluginManager();
|
||||
pluginManager.registerEvents(new SignListener(), this);
|
||||
pluginManager.registerEvents(new SignBreakListener(), this);
|
||||
|
||||
registerCommands();
|
||||
}
|
||||
@ -66,7 +85,9 @@ public final class PaidSigns extends JavaPlugin {
|
||||
public void reload() {
|
||||
this.reloadConfig();
|
||||
loadConfig();
|
||||
Translator.loadLanguages(language);
|
||||
signManager = new PaidSignManager(PaidSignManager.loadSigns());
|
||||
TrackedSignManager.loadTrackedSigns();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,27 +117,67 @@ public final class PaidSigns extends JavaPlugin {
|
||||
return this.ignoreColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether refunds are currently enabled
|
||||
*
|
||||
* @return <p>Whether refunds are currently enabled</p>
|
||||
*/
|
||||
public boolean areRefundsEnabled() {
|
||||
return this.refundsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the percentage of the initial cost to refund the sign creator
|
||||
*
|
||||
* @return <p>The percentage of the cost to refund</p>
|
||||
*/
|
||||
public short getRefundPercentage() {
|
||||
if (this.refundPercentage < 0) {
|
||||
return 0;
|
||||
} else if (refundPercentage > 100) {
|
||||
return 100;
|
||||
}
|
||||
return this.refundPercentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether refunds should always happen, even if signs are not broken by players
|
||||
*
|
||||
* @return <p>True if refunds should always happen</p>
|
||||
*/
|
||||
public boolean refundAlways() {
|
||||
return this.refundAlways;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
registerCommand("editPaidSign", new EditCommand(), new EditTabCompleter());
|
||||
|
||||
PluginCommand removeCommand = this.getCommand("removePaidSign");
|
||||
if (removeCommand != null) {
|
||||
removeCommand.setExecutor(new RemoveCommand());
|
||||
removeCommand.setTabCompleter(new RemoveTabCompleter());
|
||||
}
|
||||
TabExecutor removeTabExecutor = new RemoveTabCommand();
|
||||
registerCommand("removePaidSign", removeTabExecutor, removeTabExecutor);
|
||||
TabExecutor reloadTabExecutor = new ReloadTabCommand();
|
||||
registerCommand("reload", reloadTabExecutor, reloadTabExecutor);
|
||||
}
|
||||
|
||||
PluginCommand reloadCommand = this.getCommand("reload");
|
||||
if (reloadCommand != null) {
|
||||
TabExecutor reloadTabExecutor = new ReloadTabCommand();
|
||||
reloadCommand.setExecutor(reloadTabExecutor);
|
||||
reloadCommand.setTabCompleter(reloadTabExecutor);
|
||||
/**
|
||||
* Registers a command if possible
|
||||
*
|
||||
* @param command <p>The command to register</p>
|
||||
* @param commandExecutor <p>The command executor for executing the command</p>
|
||||
* @param tabCompleter <p>The tab completer for tab-completing the command</p>
|
||||
*/
|
||||
private void registerCommand(String command, CommandExecutor commandExecutor, TabCompleter tabCompleter) {
|
||||
PluginCommand pluginCommand = this.getCommand(command);
|
||||
if (pluginCommand != null) {
|
||||
pluginCommand.setExecutor(commandExecutor);
|
||||
pluginCommand.setTabCompleter(tabCompleter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,8 +188,13 @@ public final class PaidSigns extends JavaPlugin {
|
||||
FileConfiguration config = this.getConfig();
|
||||
config.options().copyDefaults(true);
|
||||
this.saveDefaultConfig();
|
||||
this.saveConfig();
|
||||
language = config.getString("language", "en");
|
||||
ignoreCase = config.getBoolean("ignoreCase", true);
|
||||
ignoreColor = config.getBoolean("ignoreColor", false);
|
||||
refundsEnabled = config.getBoolean("refundsEnabled", true);
|
||||
refundPercentage = (short) config.getInt("refundPercentage", 100);
|
||||
refundAlways = config.getBoolean("refundAlways", false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,7 +206,7 @@ public final class PaidSigns extends JavaPlugin {
|
||||
if (economyProvider != null) {
|
||||
EconomyManager.initialize(economyProvider.getProvider());
|
||||
} else {
|
||||
throw new IllegalStateException("[PaidSigns] Error: Vault could not be loaded");
|
||||
throw new IllegalStateException("Error: Vault could not be loaded");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,73 +2,87 @@ package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.manager.PaidSignManager;
|
||||
import net.knarcraft.paidsigns.property.OptionState;
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A representation of the command for adding a new paid sign
|
||||
*/
|
||||
public class AddCommand implements CommandExecutor {
|
||||
public class AddCommand extends TokenizedCommand {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
if (args.length < 3) {
|
||||
super.onCommand(sender, command, label, args);
|
||||
if (argumentSize < 2) {
|
||||
return false;
|
||||
}
|
||||
PaidSignManager manager = PaidSigns.getInstance().getSignManager();
|
||||
List<String> arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
|
||||
String id = arguments.get(0);
|
||||
short line;
|
||||
String signName = arguments.get(0).trim();
|
||||
double cost;
|
||||
try {
|
||||
line = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
cost = Double.parseDouble(arguments.get(2));
|
||||
cost = Double.parseDouble(arguments.get(1));
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage("You provided an invalid number");
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
String permission = "";
|
||||
if (argumentSize > 2) {
|
||||
permission = arguments.get(2);
|
||||
}
|
||||
OptionState ignoreCase = OptionState.DEFAULT;
|
||||
OptionState ignoreColor = OptionState.DEFAULT;
|
||||
if (arguments.size() > 3) {
|
||||
if (argumentSize > 3) {
|
||||
ignoreCase = OptionState.fromString(arguments.get(3));
|
||||
}
|
||||
if (arguments.size() > 4) {
|
||||
if (argumentSize > 4) {
|
||||
ignoreColor = OptionState.fromString(arguments.get(4));
|
||||
}
|
||||
boolean matchAnyCondition = false;
|
||||
if (argumentSize > 5) {
|
||||
matchAnyCondition = Boolean.parseBoolean(arguments.get(5));
|
||||
}
|
||||
|
||||
return createPaidSign(sender, signName, cost, permission, ignoreCase, ignoreColor, matchAnyCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new paid sign with the given user input
|
||||
*
|
||||
* @param sender <p>The command sender that called the add command</p>
|
||||
* @param signName <p>The name of the new paid sign</p>
|
||||
* @param cost <p>The cost of the new paid sign</p>
|
||||
* @param permission <p>The permission required for creating the sign represented by the paid sign</p>
|
||||
* @param ignoreCase <p>Whether to ignore case for the paid sign's conditions</p>
|
||||
* @param ignoreColor <p>Whether to ignore color for the paid sign's conditions</p>
|
||||
* @param matchAnyCondition <p>Whether to treat any matching condition as a sign match</p>
|
||||
* @return <p>True if the paid sign was successfully created and registered</p>
|
||||
*/
|
||||
private boolean createPaidSign(CommandSender sender, String signName, double cost, String permission,
|
||||
OptionState ignoreCase, OptionState ignoreColor, boolean matchAnyCondition) {
|
||||
PaidSignManager manager = PaidSigns.getInstance().getSignManager();
|
||||
try {
|
||||
PaidSign sign = new PaidSign(id, line, cost, ignoreCase, ignoreColor);
|
||||
for (PaidSign similarSign : manager.getPaidSigns(sign.getCleanId(), sign.getLineIndex())) {
|
||||
if (sign.matches(similarSign)) {
|
||||
sender.sendMessage("A paid sign with the same id and line already exists");
|
||||
return false;
|
||||
}
|
||||
PaidSign sign = new PaidSign(signName, cost, permission, ignoreCase, ignoreColor, matchAnyCondition);
|
||||
if (manager.getPaidSign(signName) != null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_NAME_DUPLICATE));
|
||||
return false;
|
||||
}
|
||||
manager.addPaidSign(sign);
|
||||
sender.sendMessage("Successfully added new paid sign");
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_ADDED_PAID_SIGN));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
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()));
|
||||
sender.sendMessage("An exception occurred. Please notify the server administrator or check the server log.");
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
return false;
|
||||
} catch (IllegalArgumentException e) {
|
||||
sender.sendMessage("Invalid input: " + e.getMessage());
|
||||
sender.sendMessage(StringFormatter.replacePlaceholder(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_INVALID_INPUT), "{input}", e.getMessage()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.manager.PaidSignManager;
|
||||
import net.knarcraft.paidsigns.property.OptionState;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A representation of the command for adding a new match condition for a sign
|
||||
*/
|
||||
public class AddConditionCommand extends TokenizedCommand {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
super.onCommand(sender, command, label, args);
|
||||
if (argumentSize < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = arguments.get(0);
|
||||
short lineNumber;
|
||||
try {
|
||||
lineNumber = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
if (lineNumber < 0 || lineNumber > 3) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
String stringToMatch = arguments.get(2);
|
||||
boolean executeRegEx = false;
|
||||
if (argumentSize > 3) {
|
||||
executeRegEx = Boolean.parseBoolean(arguments.get(3));
|
||||
if (executeRegEx && isRegExInvalid(sender, stringToMatch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
OptionState ignoreCase = OptionState.DEFAULT;
|
||||
if (argumentSize > 4) {
|
||||
ignoreCase = OptionState.getFromBoolean(Boolean.parseBoolean(arguments.get(4)));
|
||||
}
|
||||
OptionState ignoreColor = OptionState.DEFAULT;
|
||||
if (argumentSize > 5) {
|
||||
ignoreColor = OptionState.getFromBoolean(Boolean.parseBoolean(arguments.get(5)));
|
||||
}
|
||||
return addCondition(name, lineNumber, stringToMatch, executeRegEx, ignoreCase, ignoreColor, sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given input to add a paid sign condition
|
||||
*
|
||||
* @param name <p>The name of the paid sign to add the condition to</p>
|
||||
* @param lineNumber <p>The sign line the condition should check</p>
|
||||
* @param stringToMatch <p>The string to look for on created signs</p>
|
||||
* @param executeRegEx <p>Whether to treat the match string as a regular expression</p>
|
||||
* @param ignoreCase <p>Whether to ignore case when matching</p>
|
||||
* @param ignoreColor <p>Whether to ignore color when matching</p>
|
||||
* @param sender <p>The command sender to notify when finished</p>
|
||||
* @return <p>True if the condition was successfully added</p>
|
||||
*/
|
||||
private boolean addCondition(String name, short lineNumber, String stringToMatch, boolean executeRegEx,
|
||||
OptionState ignoreCase, OptionState ignoreColor, CommandSender sender) {
|
||||
PaidSignManager signManager = PaidSigns.getInstance().getSignManager();
|
||||
PaidSign sign = signManager.getPaidSign(name);
|
||||
if (sign == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND));
|
||||
return false;
|
||||
}
|
||||
sign.addCondition(lineNumber, stringToMatch, executeRegEx, ignoreCase, ignoreColor);
|
||||
try {
|
||||
signManager.saveSigns();
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
return false;
|
||||
}
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(
|
||||
TranslatableMessage.SUCCESS_ADDED_PAID_SIGN_CONDITION));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The tab completer for the add paid sign condition command
|
||||
*/
|
||||
public class AddConditionTabCompleter extends TokenizedTabCompleter {
|
||||
|
||||
private List<String> lineIndices;
|
||||
private List<String> stringsToMatch;
|
||||
private List<String> booleans;
|
||||
private List<String> optionStates;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
super.onTabComplete(sender, command, alias, args);
|
||||
if (lineIndices == null) {
|
||||
initializeValues();
|
||||
}
|
||||
if (argumentSize == 1) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(TabCompleteHelper.getPaidSignNames(), arguments.get(0));
|
||||
} else if (argumentSize == 2) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(this.lineIndices, arguments.get(1));
|
||||
} else if (argumentSize == 3) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(stringsToMatch, arguments.get(2));
|
||||
} else if (argumentSize == 4) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(booleans, arguments.get(3));
|
||||
} else if (argumentSize == 5) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(optionStates, arguments.get(4));
|
||||
} else if (argumentSize == 6) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(optionStates, arguments.get(5));
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the values available for tab completion
|
||||
*/
|
||||
private void initializeValues() {
|
||||
lineIndices = TabCompleteHelper.getSignLines();
|
||||
stringsToMatch = TabCompleteHelper.getExampleConditionStrings();
|
||||
booleans = TabCompleteHelper.getBooleans();
|
||||
optionStates = TabCompleteHelper.getOptionStates();
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -13,30 +12,34 @@ import java.util.List;
|
||||
/**
|
||||
* The tab completer for the add paid sign command
|
||||
*/
|
||||
public class AddTabCompleter implements TabCompleter {
|
||||
public class AddTabCompleter extends TokenizedTabCompleter {
|
||||
|
||||
private static List<String> ids;
|
||||
private static List<String> lines;
|
||||
private static List<String> names;
|
||||
private static List<String> costs;
|
||||
private static List<String> options;
|
||||
private static List<String> booleans;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
if (ids == null) {
|
||||
super.onTabComplete(sender, command, alias, args);
|
||||
if (names == null) {
|
||||
initializeValues();
|
||||
}
|
||||
List<String> arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
|
||||
if (arguments.size() < 1) {
|
||||
return ids;
|
||||
} else if (arguments.size() < 2) {
|
||||
return lines;
|
||||
} else if (arguments.size() < 3) {
|
||||
return costs;
|
||||
} else if (arguments.size() < 5) {
|
||||
return options;
|
||||
if (argumentSize == 1) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(names, arguments.get(0));
|
||||
} else if (argumentSize == 2) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(costs, arguments.get(1));
|
||||
} else if (argumentSize == 3) {
|
||||
return TabCompleteHelper.tabCompletePermission(arguments.get(arguments.size() - 1));
|
||||
} else if (argumentSize == 4) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(options, arguments.get(3));
|
||||
} else if (argumentSize == 5) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(options, arguments.get(4));
|
||||
} else if (argumentSize == 6) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(booleans, arguments.get(5));
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
@ -45,27 +48,10 @@ public class AddTabCompleter implements TabCompleter {
|
||||
* Initializes the values available for tab completion
|
||||
*/
|
||||
private static void initializeValues() {
|
||||
ids = new ArrayList<>();
|
||||
ids.add("[Gate]");
|
||||
ids.add("\"[Lift Up]\"");
|
||||
ids.add("\"[Lift Down]\"");
|
||||
|
||||
lines = new ArrayList<>();
|
||||
lines.add("1");
|
||||
lines.add("2");
|
||||
lines.add("3");
|
||||
lines.add("4");
|
||||
|
||||
costs = new ArrayList<>();
|
||||
costs.add("1");
|
||||
costs.add("5");
|
||||
costs.add("10");
|
||||
costs.add("15");
|
||||
|
||||
options = new ArrayList<>();
|
||||
options.add("default");
|
||||
options.add("true");
|
||||
options.add("false");
|
||||
names = TabCompleteHelper.getExamplePaidSignNames();
|
||||
costs = TabCompleteHelper.getCosts();
|
||||
options = TabCompleteHelper.getOptionStates();
|
||||
booleans = TabCompleteHelper.getBooleans();
|
||||
}
|
||||
|
||||
}
|
||||
|
186
src/main/java/net/knarcraft/paidsigns/command/EditCommand.java
Normal file
186
src/main/java/net/knarcraft/paidsigns/command/EditCommand.java
Normal file
@ -0,0 +1,186 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.container.PaidSignCondition;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.manager.PaidSignManager;
|
||||
import net.knarcraft.paidsigns.property.OptionState;
|
||||
import net.knarcraft.paidsigns.property.PaidSignConditionProperty;
|
||||
import net.knarcraft.paidsigns.property.PaidSignProperty;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A representation of the command for editing a new paid sign
|
||||
*/
|
||||
public class EditCommand extends TokenizedCommand {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
super.onCommand(sender, command, label, args);
|
||||
if (argumentSize < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
|
||||
if (sign == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND));
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
//First, assume a condition is changed
|
||||
return parseGivenConditionLine(sign, sender);
|
||||
} catch (NumberFormatException exception) {
|
||||
//Fall back to assume a sign is changed
|
||||
return parseGivenProperty(sign, sender);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given condition line and the rest of the input
|
||||
*
|
||||
* @param sign <p>The paid sign the user is trying to edit</p>
|
||||
* @param sender <p>The command sender to notify of any errors</p>
|
||||
* @return <p>True if the command was executed successfully</p>
|
||||
* @throws NumberFormatException <p>If the given argument is not a number</p>
|
||||
*/
|
||||
private boolean parseGivenConditionLine(@NotNull PaidSign sign,
|
||||
@NotNull CommandSender sender) throws NumberFormatException {
|
||||
short signLine = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
if (signLine < 0 || signLine > 3 || sign.getConditions().get(signLine) == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_NO_SUCH_CONDITION));
|
||||
return false;
|
||||
}
|
||||
if (argumentSize < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PaidSignConditionProperty conditionProperty = PaidSignConditionProperty.getFromString(arguments.get(2));
|
||||
if (conditionProperty == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_PROPERTY_NOT_RECOGNIZED));
|
||||
return false;
|
||||
}
|
||||
String value = arguments.get(3);
|
||||
return updateConditionProperty(sender, sign, signLine, conditionProperty, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given paid sign property and the rest of the input
|
||||
*
|
||||
* @param sign <p>The paid sign the user is trying to edit</p>
|
||||
* @param sender <p>The command sender to notify of any errors</p>
|
||||
* @return <p>True if the command was executed successfully</p>
|
||||
* @throws IOException <p>If unable to remove or save the sign</p>
|
||||
*/
|
||||
private boolean parseGivenProperty(@NotNull PaidSign sign,
|
||||
@NotNull CommandSender sender) throws IOException {
|
||||
PaidSignProperty property = PaidSignProperty.getFromString(arguments.get(1));
|
||||
if (property == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_PROPERTY_NOT_RECOGNIZED));
|
||||
return false;
|
||||
}
|
||||
String value = arguments.get(2);
|
||||
try {
|
||||
updateProperty(sender, sign, property, value);
|
||||
return true;
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a property for a paid sign
|
||||
*
|
||||
* @param sender <p>The command sender to notify of any errors or success</p>
|
||||
* @param sign <p>The sign to be updated</p>
|
||||
* @param property <p>The property to update</p>
|
||||
* @param newValue <p>The new value of the property</p>
|
||||
* @throws IOException <p>If unable to remove or save the sign</p>
|
||||
*/
|
||||
private void updateProperty(CommandSender sender, PaidSign sign, PaidSignProperty property,
|
||||
String newValue) throws IOException {
|
||||
String signName = property == PaidSignProperty.NAME ? newValue : sign.getName();
|
||||
OptionState ignoreCase = property == PaidSignProperty.IGNORE_CASE ? OptionState.fromString(newValue) :
|
||||
OptionState.getFromBoolean(sign.getIgnoreCase());
|
||||
OptionState ignoreColor = property == PaidSignProperty.IGNORE_COLOR ? OptionState.fromString(newValue) :
|
||||
OptionState.getFromBoolean(sign.getIgnoreColor());
|
||||
boolean matchAnyCondition = property == PaidSignProperty.MATCH_ANY_CONDITION ? Boolean.parseBoolean(newValue) :
|
||||
sign.matchAnyCondition();
|
||||
double cost = property == PaidSignProperty.COST ? Double.parseDouble(newValue) : sign.getCost();
|
||||
String permission = property == PaidSignProperty.PERMISSION ? newValue : sign.getPermission();
|
||||
Map<Short, PaidSignCondition> conditions = sign.getConditions();
|
||||
|
||||
PaidSignManager manager = PaidSigns.getInstance().getSignManager();
|
||||
PaidSign updatedSign = new PaidSign(signName, cost, permission, ignoreCase, ignoreColor, matchAnyCondition);
|
||||
for (short line : conditions.keySet()) {
|
||||
PaidSignCondition condition = conditions.get(line);
|
||||
updatedSign.addCondition(line, condition.getStringToMatch(), condition.executeRegex(),
|
||||
OptionState.getFromBoolean(condition.ignoreCase()),
|
||||
OptionState.getFromBoolean(condition.ignoreColor()));
|
||||
}
|
||||
manager.removePaidSign(sign.getName());
|
||||
manager.addPaidSign(updatedSign);
|
||||
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_UPDATED_PAID_SIGN));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a property of a condition of a paid sign
|
||||
*
|
||||
* @param sender <p>The command sender to notify of any errors or success</p>
|
||||
* @param sign <p>The sign the condition belongs to</p>
|
||||
* @param conditionIndex <p>The line index that identifies the sign condition</p>
|
||||
* @param property <p>The condition property to update</p>
|
||||
* @param newValue <p>The new value of the property</p>
|
||||
* @return <p>True if the property was successfully changed</p>
|
||||
*/
|
||||
private boolean updateConditionProperty(CommandSender sender, PaidSign sign, short conditionIndex,
|
||||
PaidSignConditionProperty property, String newValue) {
|
||||
PaidSignCondition condition = sign.getConditions().get(conditionIndex);
|
||||
String stringToMatch = property == PaidSignConditionProperty.STRING_TO_MATCH ? newValue :
|
||||
condition.getStringToMatch();
|
||||
boolean executeRegEx = property == PaidSignConditionProperty.EXECUTE_REG_EX ? Boolean.parseBoolean(newValue) :
|
||||
condition.executeRegex();
|
||||
boolean ignoreCase = property == PaidSignConditionProperty.IGNORE_CASE ? OptionState.getBooleanValue(
|
||||
OptionState.fromString(newValue), sign.getIgnoreCase()) : condition.ignoreCase();
|
||||
boolean ignoreColor = property == PaidSignConditionProperty.IGNORE_COLOR ? OptionState.getBooleanValue(
|
||||
OptionState.fromString(newValue), sign.getIgnoreColor()) : condition.ignoreColor();
|
||||
|
||||
//Make sure to test the regular expression in case anything changed
|
||||
if (executeRegEx && isRegExInvalid(sender, stringToMatch)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sign.addCondition(conditionIndex, stringToMatch, executeRegEx, OptionState.getFromBoolean(ignoreCase),
|
||||
OptionState.getFromBoolean(ignoreColor));
|
||||
|
||||
try {
|
||||
PaidSigns.getInstance().getSignManager().saveSigns();
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
return false;
|
||||
}
|
||||
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(
|
||||
TranslatableMessage.SUCCESS_UPDATED_PAID_SIGN_CONDITION));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,176 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.property.PaidSignConditionProperty;
|
||||
import net.knarcraft.paidsigns.property.PaidSignProperty;
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The tab completer for the edit paid sign command
|
||||
*/
|
||||
public class EditTabCompleter extends TokenizedTabCompleter {
|
||||
|
||||
private static Map<PaidSignProperty, List<String>> propertyExampleValues;
|
||||
private static Map<PaidSignConditionProperty, List<String>> conditionPropertyExampleValues;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
super.onTabComplete(sender, command, label, args);
|
||||
if (propertyExampleValues == null) {
|
||||
initializePropertyExampleValues();
|
||||
initializeConditionPropertyExampleValues();
|
||||
}
|
||||
|
||||
if (argumentSize == 1) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(TabCompleteHelper.getPaidSignNames(), arguments.get(0));
|
||||
} else if (argumentSize >= 2) {
|
||||
PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
|
||||
if (sign != null) {
|
||||
return tabCompleteForSign(sign);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tab completions for the given, non-null sign
|
||||
*
|
||||
* @param sign <p>The sign to tab complete for</p>
|
||||
* @return <p>The tab complete options to give to users</p>
|
||||
*/
|
||||
private List<String> tabCompleteForSign(@NotNull PaidSign sign) {
|
||||
if (argumentSize == 2) {
|
||||
List<String> conditions = getAvailableSignConditions(sign);
|
||||
conditions.addAll(getPaidSignProperties());
|
||||
return TabCompleteHelper.filterMatchingStartsWith(conditions, arguments.get(1));
|
||||
} else if (argumentSize >= 3) {
|
||||
try {
|
||||
return tabCompleteSignLine(sign);
|
||||
} catch (NumberFormatException exception) {
|
||||
if (argumentSize == 3) {
|
||||
return tabCompleteProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tab completions for the selected sign line
|
||||
*
|
||||
* @param sign <p>The paid sign the line belongs to</p>
|
||||
* @return <p>The tab complete options to give to users</p>
|
||||
*/
|
||||
private List<String> tabCompleteSignLine(@NotNull PaidSign sign) {
|
||||
short signLine = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
//Refuse to autocomplete if invalid input is given
|
||||
if (signLine < 0 || signLine > 3 || sign.getConditions().get(signLine) == null) {
|
||||
return new ArrayList<>();
|
||||
} else if (argumentSize == 3) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(getPaidSignConditionProperties(), arguments.get(2));
|
||||
} else if (argumentSize == 4) {
|
||||
PaidSignConditionProperty property = PaidSignConditionProperty.getFromString(arguments.get(2));
|
||||
if (property != null) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(conditionPropertyExampleValues.get(property),
|
||||
arguments.get(3));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns tab completions for the selected property
|
||||
*
|
||||
* @return <p>The tab complete options to give to users</p>
|
||||
*/
|
||||
private List<String> tabCompleteProperty() {
|
||||
PaidSignProperty paidSignProperty = PaidSignProperty.getFromString(arguments.get(1));
|
||||
if (paidSignProperty != null) {
|
||||
if (paidSignProperty == PaidSignProperty.PERMISSION) {
|
||||
return TabCompleteHelper.tabCompletePermission(arguments.get(2));
|
||||
} else {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(propertyExampleValues.get(paidSignProperty),
|
||||
arguments.get(2));
|
||||
}
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all paid sign condition properties
|
||||
*
|
||||
* @return <p>All paid sign condition properties</p>
|
||||
*/
|
||||
private List<String> getPaidSignConditionProperties() {
|
||||
List<String> properties = new ArrayList<>();
|
||||
for (PaidSignConditionProperty property : PaidSignConditionProperty.values()) {
|
||||
properties.add(property.getStringRepresentation());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all paid sign properties
|
||||
*
|
||||
* @return <p>All paid sign properties</p>
|
||||
*/
|
||||
private List<String> getPaidSignProperties() {
|
||||
List<String> properties = new ArrayList<>();
|
||||
for (PaidSignProperty property : PaidSignProperty.values()) {
|
||||
properties.add(property.getStringRepresentation());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all sign conditions available for the given sign
|
||||
*
|
||||
* @param sign <p>The sign to get available sign conditions for</p>
|
||||
* @return <p>The available sign conditions</p>
|
||||
*/
|
||||
private List<String> getAvailableSignConditions(PaidSign sign) {
|
||||
List<String> availableConditions = new ArrayList<>();
|
||||
for (Short signLine : sign.getConditions().keySet()) {
|
||||
availableConditions.add(String.valueOf(signLine + 1));
|
||||
}
|
||||
return availableConditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the map for paid sign property example tab completions
|
||||
*/
|
||||
private void initializePropertyExampleValues() {
|
||||
propertyExampleValues = new HashMap<>();
|
||||
propertyExampleValues.put(PaidSignProperty.COST, TabCompleteHelper.getCosts());
|
||||
propertyExampleValues.put(PaidSignProperty.NAME, TabCompleteHelper.getPaidSignNames());
|
||||
propertyExampleValues.put(PaidSignProperty.IGNORE_CASE, TabCompleteHelper.getOptionStates());
|
||||
propertyExampleValues.put(PaidSignProperty.IGNORE_COLOR, TabCompleteHelper.getOptionStates());
|
||||
propertyExampleValues.put(PaidSignProperty.MATCH_ANY_CONDITION, TabCompleteHelper.getBooleans());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the map for paid sign condition property example tab completions
|
||||
*/
|
||||
private void initializeConditionPropertyExampleValues() {
|
||||
conditionPropertyExampleValues = new HashMap<>();
|
||||
conditionPropertyExampleValues.put(PaidSignConditionProperty.STRING_TO_MATCH,
|
||||
TabCompleteHelper.getExampleConditionStrings());
|
||||
conditionPropertyExampleValues.put(PaidSignConditionProperty.IGNORE_COLOR, TabCompleteHelper.getOptionStates());
|
||||
conditionPropertyExampleValues.put(PaidSignConditionProperty.IGNORE_CASE, TabCompleteHelper.getOptionStates());
|
||||
conditionPropertyExampleValues.put(PaidSignConditionProperty.EXECUTE_REG_EX, TabCompleteHelper.getBooleans());
|
||||
}
|
||||
|
||||
}
|
130
src/main/java/net/knarcraft/paidsigns/command/ListCommand.java
Normal file
130
src/main/java/net/knarcraft/paidsigns/command/ListCommand.java
Normal file
@ -0,0 +1,130 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.container.PaidSignCondition;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.formatting.Translator;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static net.knarcraft.paidsigns.formatting.StringFormatter.getTranslatedErrorMessage;
|
||||
import static net.knarcraft.paidsigns.formatting.StringFormatter.replacePlaceholder;
|
||||
import static net.knarcraft.paidsigns.formatting.StringFormatter.replacePlaceholders;
|
||||
import static net.knarcraft.paidsigns.formatting.StringFormatter.translateBoolean;
|
||||
|
||||
/**
|
||||
* A representation of the command for listing information about paid signs
|
||||
*/
|
||||
public class ListCommand extends TokenizedCommand {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
super.onCommand(sender, command, label, args);
|
||||
if (argumentSize < 1) {
|
||||
displaySigns(sender);
|
||||
return true;
|
||||
} else if (argumentSize < 3) {
|
||||
return parsePaidSignSelection(sender);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays all available signs
|
||||
*
|
||||
* @param sender <p>The command sender to display the signs to</p>
|
||||
*/
|
||||
private void displaySigns(CommandSender sender) {
|
||||
StringBuilder signs = new StringBuilder();
|
||||
for (String signName : PaidSigns.getInstance().getSignManager().getAllPaidSigns().keySet()) {
|
||||
signs.append(StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(
|
||||
TranslatableMessage.PAID_SIGNS_INFO_FORMAT), "{name}", signName));
|
||||
}
|
||||
sender.sendMessage(StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(
|
||||
TranslatableMessage.PAID_SIGNS_INFO), "{signs}", signs.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given input and displays the wanted paid-sign information
|
||||
*
|
||||
* @param sender <p>The command sender to display the information to</p>
|
||||
* @return <p>True if successful. False if the input contained errors</p>
|
||||
*/
|
||||
private boolean parsePaidSignSelection(CommandSender sender) {
|
||||
PaidSign paidSign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
|
||||
if (paidSign == null) {
|
||||
sender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND));
|
||||
return false;
|
||||
}
|
||||
if (argumentSize < 2) {
|
||||
displayPaidSign(sender, paidSign);
|
||||
} else {
|
||||
short lineNumber;
|
||||
try {
|
||||
lineNumber = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
if (lineNumber < 0 || lineNumber > 3) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
if (!paidSign.getConditions().containsKey(lineNumber)) {
|
||||
sender.sendMessage(replacePlaceholder(getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_NO_SUCH_CONDITION), "{line}", String.valueOf(lineNumber)));
|
||||
return false;
|
||||
}
|
||||
PaidSignCondition condition = paidSign.getConditions().get(lineNumber);
|
||||
displayPaidSignCondition(sender, paidSign.getName(), lineNumber, condition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information about a paid sign condition
|
||||
*
|
||||
* @param sender <p>The command sender to display the information to</p>
|
||||
* @param signName <p>The name of the sign to display the condition for</p>
|
||||
* @param signLine <p>The line the condition is for</p>
|
||||
* @param condition <p>The condition to display information about</p>
|
||||
*/
|
||||
private void displayPaidSignCondition(CommandSender sender, String signName, short signLine,
|
||||
PaidSignCondition condition) {
|
||||
sender.sendMessage(StringFormatter.replacePlaceholders(Translator.getTranslatedMessage(
|
||||
TranslatableMessage.PAID_SIGN_CONDITION_INFO), new String[]{"{name}", "{line}", "{match}", "{regex}",
|
||||
"{case}", "{color}"}, new String[]{signName, String.valueOf(signLine + 1), condition.getStringToMatch(),
|
||||
translateBoolean(condition.executeRegex()), translateBoolean(condition.ignoreCase()),
|
||||
translateBoolean(condition.ignoreColor())}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays information about a paid sign
|
||||
*
|
||||
* @param sender <p>The command sender to display the information to</p>
|
||||
* @param paidSign <p>The paid sign to display information about</p>
|
||||
*/
|
||||
private void displayPaidSign(CommandSender sender, PaidSign paidSign) {
|
||||
Map<Short, PaidSignCondition> signConditions = paidSign.getConditions();
|
||||
StringBuilder conditions = new StringBuilder();
|
||||
for (short lineIndex : signConditions.keySet()) {
|
||||
String format = Translator.getTranslatedMessage(TranslatableMessage.PAID_SIGN_INFO_CONDITION_FORMAT);
|
||||
conditions.append(StringFormatter.replacePlaceholders(format, new String[]{"{line}", "{condition}"},
|
||||
new String[]{String.valueOf((lineIndex + 1)), signConditions.get(lineIndex).getStringToMatch()}));
|
||||
}
|
||||
|
||||
sender.sendMessage(replacePlaceholders(Translator.getTranslatedMessage(
|
||||
TranslatableMessage.PAID_SIGN_INFO), new String[]{"{name}", "{cost}", "{permission}", "{case}",
|
||||
"{color}", "{any}", "{conditions}"}, new String[]{paidSign.getName(), String.valueOf(paidSign.getCost()),
|
||||
paidSign.getPermission(), translateBoolean(paidSign.getIgnoreCase()),
|
||||
translateBoolean(paidSign.getIgnoreColor()), translateBoolean(paidSign.matchAnyCondition()),
|
||||
conditions.toString()}));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The tab completer for the list paid signs command
|
||||
*/
|
||||
public class ListTabCompleter extends TokenizedTabCompleter {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
super.onTabComplete(sender, command, alias, args);
|
||||
if (argumentSize == 1) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(TabCompleteHelper.getPaidSignNames(), arguments.get(0));
|
||||
} else if (argumentSize == 2) {
|
||||
PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
|
||||
if (sign != null) {
|
||||
List<String> availableConditions = new ArrayList<>();
|
||||
for (Short signLine : sign.getConditions().keySet()) {
|
||||
availableConditions.add(String.valueOf(signLine + 1));
|
||||
}
|
||||
return TabCompleteHelper.filterMatchingStartsWith(availableConditions, arguments.get(1));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
@ -18,7 +20,8 @@ public class ReloadTabCommand implements TabExecutor {
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
PaidSigns.getInstance().reload();
|
||||
return false;
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_RELOADED));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,55 +0,0 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A representation of the command for removing a paid sign
|
||||
*/
|
||||
public class RemoveCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
if (args.length < 1) {
|
||||
return false;
|
||||
}
|
||||
List<String> arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
String[] input = arguments.get(0).split("\\|");
|
||||
short line;
|
||||
try {
|
||||
line = (short) (Short.parseShort(input[0]) - 1);
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage("Invalid line number given");
|
||||
return false;
|
||||
}
|
||||
String id = String.join("|", (String[]) ArrayUtils.remove(input, 0));
|
||||
try {
|
||||
if (PaidSigns.getInstance().getSignManager().removePaidSign(id, line)) {
|
||||
sender.sendMessage("Successfully removed paid sign");
|
||||
} else {
|
||||
sender.sendMessage("No matching paid sign was found");
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
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()));
|
||||
sender.sendMessage("An exception occurred. Please notify the server administrator or check the server log.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.manager.PaidSignManager;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A representation of the command for removing a condition from a sign
|
||||
*/
|
||||
public class RemoveConditionCommand extends TokenizedCommand {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
super.onCommand(sender, command, label, args);
|
||||
if (argumentSize < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name = arguments.get(0);
|
||||
short lineNumber;
|
||||
try {
|
||||
lineNumber = (short) (Short.parseShort(arguments.get(1)) - 1);
|
||||
if (lineNumber < 0 || lineNumber > 3) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER));
|
||||
return false;
|
||||
}
|
||||
PaidSignManager signManager = PaidSigns.getInstance().getSignManager();
|
||||
PaidSign sign = signManager.getPaidSign(name);
|
||||
if (sign == null) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sign.getConditions().containsKey(lineNumber)) {
|
||||
sender.sendMessage(StringFormatter.replacePlaceholder(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_NO_SUCH_CONDITION), "{line}", String.valueOf((lineNumber + 1))));
|
||||
return false;
|
||||
}
|
||||
|
||||
sign.removeCondition(lineNumber);
|
||||
try {
|
||||
signManager.saveSigns();
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
return false;
|
||||
}
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_REMOVED_CONDITION));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The tab completer for the remove paid sign condition command
|
||||
*/
|
||||
public class RemoveConditionTabCompleter extends TokenizedTabCompleter {
|
||||
|
||||
private List<String> lineIndices;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
super.onTabComplete(sender, command, alias, args);
|
||||
if (lineIndices == null) {
|
||||
initializeValues();
|
||||
}
|
||||
|
||||
if (argumentSize == 1) {
|
||||
return TabCompleteHelper.filterMatchingStartsWith(TabCompleteHelper.getPaidSignNames(), arguments.get(0));
|
||||
} else if (argumentSize == 2) {
|
||||
PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
|
||||
if (sign != null) {
|
||||
List<String> availableConditions = new ArrayList<>();
|
||||
for (Short signLine : sign.getConditions().keySet()) {
|
||||
availableConditions.add(String.valueOf(signLine + 1));
|
||||
}
|
||||
return TabCompleteHelper.filterMatchingStartsWith(availableConditions, arguments.get(1));
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the values available for tab completion
|
||||
*/
|
||||
private void initializeValues() {
|
||||
lineIndices = TabCompleteHelper.getSignLines();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A representation of the command for removing a paid sign
|
||||
*/
|
||||
public class RemoveTabCommand implements TabExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] args) {
|
||||
List<String> arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
if (arguments.size() < 1) {
|
||||
return false;
|
||||
}
|
||||
String name = arguments.get(0);
|
||||
|
||||
try {
|
||||
if (PaidSigns.getInstance().getSignManager().removePaidSign(name)) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedInfoMessage(
|
||||
TranslatableMessage.SUCCESS_REMOVED_PAID_SIGN));
|
||||
} else {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND));
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
List<String> arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
int argumentSize = args[args.length - 1].isEmpty() ? arguments.size() : arguments.size() - 1;
|
||||
|
||||
if (argumentSize < 1) {
|
||||
return TabCompleteHelper.getPaidSignNames();
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The tab completer for the remove command
|
||||
*/
|
||||
public class RemoveTabCompleter implements TabCompleter {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
List<PaidSign> allPaidSigns = PaidSigns.getInstance().getSignManager().getAllPaidSigns();
|
||||
List<String> signIds = new ArrayList<>();
|
||||
for (PaidSign sign : allPaidSigns) {
|
||||
signIds.add("\"" + (sign.getLineIndex() + 1) + "|" + sign.getId() + "\"");
|
||||
}
|
||||
return signIds;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
/**
|
||||
* A command executor with tokenized arguments
|
||||
*/
|
||||
public class TokenizedCommand implements CommandExecutor {
|
||||
|
||||
protected List<String> arguments;
|
||||
protected int argumentSize;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||
arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
argumentSize = arguments.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given regular expression is valid
|
||||
*
|
||||
* @param sender <p>The command sender to notify if the regular expression is invalid</p>
|
||||
* @param regularExpression <p>The regular expression to test</p>
|
||||
* @return <p>True if the regular expression is invalid</p>
|
||||
*/
|
||||
protected boolean isRegExInvalid(CommandSender sender, String regularExpression) {
|
||||
try {
|
||||
Pattern.compile(regularExpression);
|
||||
return false;
|
||||
} catch (PatternSyntaxException exception) {
|
||||
sender.sendMessage(StringFormatter.getTranslatedErrorMessage(
|
||||
TranslatableMessage.ERROR_INVALID_REGULAR_EXPRESSION));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.knarcraft.paidsigns.command;
|
||||
|
||||
import net.knarcraft.paidsigns.utility.Tokenizer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A tab completer with tokenized arguments
|
||||
*/
|
||||
public class TokenizedTabCompleter implements TabCompleter {
|
||||
|
||||
protected List<String> arguments;
|
||||
protected int argumentSize;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] args) {
|
||||
arguments = Tokenizer.tokenize(String.join(" ", args));
|
||||
if (args.length == 0) {
|
||||
argumentSize = 0;
|
||||
} else {
|
||||
if (args[args.length - 1].isEmpty()) {
|
||||
arguments.add("");
|
||||
}
|
||||
argumentSize = arguments.size();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -2,58 +2,59 @@ package net.knarcraft.paidsigns.container;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.property.OptionState;
|
||||
import net.knarcraft.paidsigns.utility.ColorHelper;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A representation of a paid sign
|
||||
*/
|
||||
public class PaidSign {
|
||||
|
||||
private final String id;
|
||||
private final String cleanId;
|
||||
private final short lineIndex;
|
||||
private final String name;
|
||||
private final double cost;
|
||||
private final String permission;
|
||||
private final OptionState ignoreCase;
|
||||
private final OptionState ignoreColor;
|
||||
private final boolean matchAnyCondition;
|
||||
private final Map<Short, PaidSignCondition> conditions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Instantiates a new paid sign
|
||||
*
|
||||
* @param id <p>The string that identifies this type of paid sign</p>
|
||||
* @param lineIndex <p>The line the id has to be on to trigger payment</p>
|
||||
* @param cost <p>The cost of creating this paid sign</p>
|
||||
* @param ignoreCase <p>Whether to ignore case when looking for this permission sign</p>
|
||||
* @param ignoreColor <p>Whether to ignore color when looking for this permission sign</p>
|
||||
* @param name <p>A recognizable, unique, name used to identify this paid sign</p>
|
||||
* @param cost <p>The cost of creating this paid sign</p>
|
||||
* @param permission <p>The permission required to create the sign this paid sign matches</p>
|
||||
* @param ignoreCase <p>Whether to ignore case when looking for this permission sign</p>
|
||||
* @param ignoreColor <p>Whether to ignore color when looking for this permission sign</p>
|
||||
* @param matchAnyCondition <p>Whether to treat a match for any condition as a sign match</p>
|
||||
*/
|
||||
public PaidSign(String id, short lineIndex, double cost, OptionState ignoreCase, OptionState ignoreColor) {
|
||||
if (id == null || id.trim().isBlank()) {
|
||||
throw new IllegalArgumentException("Id cannot be empty");
|
||||
public PaidSign(String name, double cost, String permission, OptionState ignoreCase, OptionState ignoreColor,
|
||||
boolean matchAnyCondition) {
|
||||
if (name == null || name.trim().isBlank()) {
|
||||
throw new IllegalArgumentException("Name cannot be empty");
|
||||
}
|
||||
if (cost <= 0) {
|
||||
throw new IllegalArgumentException("Cost must be larger than 0");
|
||||
}
|
||||
if (lineIndex < 0 || lineIndex > 3) {
|
||||
throw new IllegalArgumentException("Sign line must be between 0 and 3");
|
||||
}
|
||||
if (ignoreCase == null || ignoreColor == null) {
|
||||
throw new IllegalArgumentException("Ignore case and ignore color options cannot be null");
|
||||
}
|
||||
this.id = id;
|
||||
this.lineIndex = lineIndex;
|
||||
this.name = name;
|
||||
this.cost = cost;
|
||||
this.permission = permission;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.ignoreColor = ignoreColor;
|
||||
this.cleanId = getCleanString(id);
|
||||
this.matchAnyCondition = matchAnyCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id string of this paid sign
|
||||
* Gets the name identifying this paid sign
|
||||
*
|
||||
* @return <p>The id string of this paid sign</p>
|
||||
* @return <p>The name identifying this paid sign</p>
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,66 +67,21 @@ public class PaidSign {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the line on the sign the id must be on to trigger payment
|
||||
* Gets the permission required by a player to create the sign this paid sign matches
|
||||
*
|
||||
* @return <p>The sign line to search for the id</p>
|
||||
* @return <p>The permission required by a player to create the sign this paid sign matches</p>
|
||||
*/
|
||||
public short getLineIndex() {
|
||||
return lineIndex;
|
||||
public String getPermission() {
|
||||
return this.permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clean id of this paid sign
|
||||
* Gets all conditions registered for this paid sign
|
||||
*
|
||||
* @return <p>The clean id of this paid sign</p>
|
||||
* @return <p>All conditions registered for this paid sign</p>
|
||||
*/
|
||||
public String getCleanId() {
|
||||
return cleanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "clean" version of the given string
|
||||
*
|
||||
* <p>The "cleaning" removes color codes and lower-cases the string.</p>
|
||||
*
|
||||
* @param string <p>The string to clean</p>
|
||||
* @return <p>The cleaned string</p>
|
||||
*/
|
||||
public static String getCleanString(String string) {
|
||||
return ChatColor.stripColor(ColorHelper.translateAllColorCodes(string.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this paid sign matches the given line
|
||||
*
|
||||
* @param lineNumber <p>The line number of the given line</p>
|
||||
* @param line <p>The line to compare against this paid sign's id</p>
|
||||
* @return <p>True if the line matches this sign</p>
|
||||
*/
|
||||
public boolean matches(short lineNumber, String line) {
|
||||
if (lineNumber != this.lineIndex) {
|
||||
return false;
|
||||
}
|
||||
String idCopy = id;
|
||||
if (getIgnoreCase()) {
|
||||
idCopy = idCopy.toLowerCase();
|
||||
line = line.toLowerCase();
|
||||
}
|
||||
if (getIgnoreColor()) {
|
||||
idCopy = ColorHelper.stripColorCodes(idCopy);
|
||||
line = ColorHelper.stripColorCodes(line);
|
||||
}
|
||||
return idCopy.equals(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this paid sign matches another paid sign
|
||||
*
|
||||
* @param paidSign <p>The other paid sign to compare to</p>
|
||||
* @return <p>True if the signs match</p>
|
||||
*/
|
||||
public boolean matches(PaidSign paidSign) {
|
||||
return matches(paidSign.lineIndex, paidSign.id);
|
||||
public Map<Short, PaidSignCondition> getConditions() {
|
||||
return new HashMap<>(this.conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,11 +90,7 @@ public class PaidSign {
|
||||
* @return <p>Whether the text case should be ignored for this paid sign</p>
|
||||
*/
|
||||
public boolean getIgnoreCase() {
|
||||
if (this.ignoreCase == OptionState.DEFAULT) {
|
||||
return PaidSigns.getInstance().ignoreCase();
|
||||
} else {
|
||||
return OptionState.getBooleanValue(this.ignoreCase);
|
||||
}
|
||||
return OptionState.getBooleanValue(this.ignoreCase, PaidSigns.getInstance().ignoreCase());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,11 +99,71 @@ public class PaidSign {
|
||||
* @return <p>Whether the text color should be ignored for this paid sign</p>
|
||||
*/
|
||||
public boolean getIgnoreColor() {
|
||||
if (this.ignoreColor == OptionState.DEFAULT) {
|
||||
return PaidSigns.getInstance().ignoreColor();
|
||||
} else {
|
||||
return OptionState.getBooleanValue(this.ignoreColor);
|
||||
return OptionState.getBooleanValue(this.ignoreColor, PaidSigns.getInstance().ignoreColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to treat a match for any condition as a sign match
|
||||
*
|
||||
* @return <p>Whether to treat a match for any condition as a sign match</p>
|
||||
*/
|
||||
public boolean matchAnyCondition() {
|
||||
return this.matchAnyCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this paid sign matches the given set of sign lines
|
||||
*
|
||||
* @param lines <p>The sign lines to test against</p>
|
||||
* @return <p>True if this paid sign matches the given lines</p>
|
||||
*/
|
||||
public boolean matches(String[] lines) {
|
||||
//Make sure a paid sign without a condition never matches anything
|
||||
if (this.conditions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean matchAny = matchAnyCondition();
|
||||
boolean success = !matchAny;
|
||||
for (short i = 0; i < 4; i++) {
|
||||
PaidSignCondition condition = this.conditions.get(i);
|
||||
if (condition != null) {
|
||||
boolean conditionMatches = condition.test(lines[i]);
|
||||
if (matchAny) {
|
||||
success |= conditionMatches;
|
||||
} else {
|
||||
success &= conditionMatches;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to this paid sign
|
||||
*
|
||||
* @param line <p>The line on the sign the matched text must be on</p>
|
||||
* @param stringToMatch <p>The string that should be matched for the new condition to be true</p>
|
||||
* @param executeRegex <p>Whether to execute the string as RegEx</p>
|
||||
* @param ignoreCase <p>Whether to ignore case when matching against the condition</p>
|
||||
* @param ignoreColor <p>Whether to ignore color when matching against the condition</p>
|
||||
*/
|
||||
public void addCondition(short line, String stringToMatch, boolean executeRegex, OptionState ignoreCase, OptionState ignoreColor) {
|
||||
if (line < 0 || line > 3) {
|
||||
throw new IllegalArgumentException("Invalid sign line given for new paid sign condition");
|
||||
}
|
||||
boolean ignoreCaseBoolean = OptionState.getBooleanValue(ignoreCase, this.getIgnoreCase());
|
||||
boolean ignoreColorBoolean = OptionState.getBooleanValue(ignoreColor, this.getIgnoreColor());
|
||||
this.conditions.put(line, new PaidSignCondition(stringToMatch, executeRegex, ignoreCaseBoolean, ignoreColorBoolean));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a condition from this paid sign
|
||||
*
|
||||
* @param line <p>The sign line the condition belongs to</p>
|
||||
*/
|
||||
public void removeCondition(short line) {
|
||||
this.conditions.remove(line);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
package net.knarcraft.paidsigns.container;
|
||||
|
||||
import net.knarcraft.paidsigns.utility.ColorHelper;
|
||||
|
||||
/**
|
||||
* A condition for deciding if a paid sign matches a sign line
|
||||
*/
|
||||
public class PaidSignCondition {
|
||||
|
||||
final String stringToMatch;
|
||||
final boolean executeRegex;
|
||||
final boolean ignoreCase;
|
||||
final boolean ignoreColor;
|
||||
|
||||
/**
|
||||
* Instantiates a new paid sign condition
|
||||
*
|
||||
* @param stringToMatch <p>The string/regular expression the line has to match to fulfill this condition</p>
|
||||
* @param executeRegex <p>Whether to execute the match string as a regular expression</p>
|
||||
* @param ignoreCase <p>Whether to ignore uppercase/lowercase when comparing against this condition</p>
|
||||
* @param ignoreColor <p>Whether to ignore color codes when comparing against this condition</p>
|
||||
*/
|
||||
public PaidSignCondition(String stringToMatch, boolean executeRegex, boolean ignoreCase, boolean ignoreColor) {
|
||||
this.stringToMatch = stringToMatch;
|
||||
this.executeRegex = executeRegex;
|
||||
this.ignoreCase = ignoreCase;
|
||||
this.ignoreColor = ignoreColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string this condition should match
|
||||
*
|
||||
* @return <p>The string this condition should match</p>
|
||||
*/
|
||||
public String getStringToMatch() {
|
||||
return this.stringToMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to execute the match string as RegEx
|
||||
*
|
||||
* @return <p>Whether to execute the match string as RegEx</p>
|
||||
*/
|
||||
public boolean executeRegex() {
|
||||
return this.executeRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to ignore case when trying to match strings
|
||||
*
|
||||
* @return <p>Whether to ignore case when trying to match strings</p>
|
||||
*/
|
||||
public boolean ignoreCase() {
|
||||
return this.ignoreCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether to ignore color when trying to match strings
|
||||
*
|
||||
* @return <p>Whether to ignore color when trying to match strings</p>
|
||||
*/
|
||||
public boolean ignoreColor() {
|
||||
return this.ignoreColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given line matches this condition
|
||||
*
|
||||
* @param line <p>The sign line to test</p>
|
||||
* @return <p>True if this condition matches the given line</p>
|
||||
*/
|
||||
public boolean test(String line) {
|
||||
String stringToMatch = this.stringToMatch;
|
||||
//Strip color codes if they shouldn't matter
|
||||
if (this.ignoreColor) {
|
||||
stringToMatch = ColorHelper.stripColorCodes(stringToMatch);
|
||||
line = ColorHelper.stripColorCodes(line);
|
||||
}
|
||||
if (this.executeRegex) {
|
||||
//Match using RegEx
|
||||
if (this.ignoreCase) {
|
||||
return line.matches("(?i)" + stringToMatch);
|
||||
} else {
|
||||
return line.matches(stringToMatch);
|
||||
}
|
||||
} else {
|
||||
//Match regularly
|
||||
if (this.ignoreCase) {
|
||||
return stringToMatch.equalsIgnoreCase(line);
|
||||
} else {
|
||||
return stringToMatch.equals(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 playerId <p>The unique id of the player that created the sign</p>
|
||||
* @param cost <p>The cost the player paid for creating the sign</p>
|
||||
*/
|
||||
public TrackedSign(UUID playerId, double cost) {
|
||||
this.playerId = playerId;
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the player that created this tracked sign
|
||||
*
|
||||
* @return <p>The player that created this tracked sign</p>
|
||||
*/
|
||||
public UUID getPlayerId() {
|
||||
return this.playerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cost the player paid for creating this paid sign
|
||||
*
|
||||
* @return <p>The cost paid for creating this sign</p>
|
||||
*/
|
||||
public double getCost() {
|
||||
return this.cost;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package net.knarcraft.paidsigns.formatting;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A formatter for formatting displayed messages
|
||||
*/
|
||||
public final class StringFormatter {
|
||||
|
||||
private StringFormatter() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given boolean value
|
||||
*
|
||||
* @param booleanValue <p>The boolean value to translate</p>
|
||||
* @return <p>The translation of the boolean value</p>
|
||||
*/
|
||||
public static String translateBoolean(boolean booleanValue) {
|
||||
if (booleanValue) {
|
||||
return Translator.getTranslatedMessage(TranslatableMessage.BOOLEAN_TRUE);
|
||||
} else {
|
||||
return Translator.getTranslatedMessage(TranslatableMessage.BOOLEAN_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces a placeholder in a string
|
||||
*
|
||||
* @param input <p>The input string to replace in</p>
|
||||
* @param placeholder <p>The placeholder to replace</p>
|
||||
* @param replacement <p>The replacement value</p>
|
||||
* @return <p>The input string with the placeholder replaced</p>
|
||||
*/
|
||||
public static String replacePlaceholder(String input, String placeholder, String replacement) {
|
||||
return input.replace(placeholder, replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces placeholders in a string
|
||||
*
|
||||
* @param input <p>The input string to replace in</p>
|
||||
* @param placeholders <p>The placeholders to replace</p>
|
||||
* @param replacements <p>The replacement values</p>
|
||||
* @return <p>The input string with placeholders replaced</p>
|
||||
*/
|
||||
public static String replacePlaceholders(String input, String[] placeholders, String[] replacements) {
|
||||
for (int i = 0; i < Math.min(placeholders.length, replacements.length); i++) {
|
||||
input = replacePlaceholder(input, placeholders[i], replacements[i]);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a translated and formatted info message
|
||||
*
|
||||
* @param translatableMessage <p>The translatable message to translate and format</p>
|
||||
* @return <p>The translated and formatted message</p>
|
||||
*/
|
||||
public static String getTranslatedInfoMessage(TranslatableMessage translatableMessage) {
|
||||
return formatInfoMessage(Translator.getTranslatedMessage(translatableMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a translated and formatted error message
|
||||
*
|
||||
* @param translatableMessage <p>The translatable message to translate and format</p>
|
||||
* @return <p>The translated and formatted message</p>
|
||||
*/
|
||||
public static String getTranslatedErrorMessage(TranslatableMessage translatableMessage) {
|
||||
return formatErrorMessage(Translator.getTranslatedMessage(translatableMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an information message by adding the prefix and text color
|
||||
*
|
||||
* @param message <p>The message to format</p>
|
||||
* @return <p>The formatted message</p>
|
||||
*/
|
||||
public static String formatInfoMessage(String message) {
|
||||
return ChatColor.DARK_GREEN + formatMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an error message by adding the prefix and text color
|
||||
*
|
||||
* @param message <p>The message to format</p>
|
||||
* @return <p>The formatted message</p>
|
||||
*/
|
||||
public static String formatErrorMessage(String message) {
|
||||
return ChatColor.DARK_RED + formatMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates all found color codes to formatting in a string
|
||||
*
|
||||
* @param message <p>The string to search for color codes</p>
|
||||
* @return <p>The message with color codes translated</p>
|
||||
*/
|
||||
public static String translateAllColorCodes(String message) {
|
||||
message = ChatColor.translateAlternateColorCodes('&', message);
|
||||
Pattern pattern = Pattern.compile("(#[a-fA-F0-9]{6})");
|
||||
Matcher matcher = pattern.matcher(message);
|
||||
while (matcher.find()) {
|
||||
message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group()));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a message by adding the prefix and text color
|
||||
*
|
||||
* @param message <p>The message to format</p>
|
||||
* @return <p>The formatted message</p>
|
||||
*/
|
||||
private static String formatMessage(String message) {
|
||||
return Translator.getTranslatedMessage(TranslatableMessage.PREFIX) + " " +
|
||||
ChatColor.RESET + message;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package net.knarcraft.paidsigns.formatting;
|
||||
|
||||
/**
|
||||
* An enum representing all translatable messages
|
||||
*/
|
||||
public enum TranslatableMessage {
|
||||
|
||||
/**
|
||||
* The prefix to display in messages
|
||||
*/
|
||||
PREFIX,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign is successfully added
|
||||
*/
|
||||
SUCCESS_ADDED_PAID_SIGN,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign condition is successfully added
|
||||
*/
|
||||
SUCCESS_ADDED_PAID_SIGN_CONDITION,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign is successfully updated
|
||||
*/
|
||||
SUCCESS_UPDATED_PAID_SIGN,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign condition is successfully updated
|
||||
*/
|
||||
SUCCESS_UPDATED_PAID_SIGN_CONDITION,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign has been successfully removed
|
||||
*/
|
||||
SUCCESS_REMOVED_PAID_SIGN,
|
||||
|
||||
/**
|
||||
* The message to display when a paid sign condition has been successfully removed
|
||||
*/
|
||||
SUCCESS_REMOVED_CONDITION,
|
||||
|
||||
/**
|
||||
* The message to display after the plugin has been reloaded
|
||||
*/
|
||||
SUCCESS_RELOADED,
|
||||
|
||||
/**
|
||||
* The message to display when a player has been charged for creating a paid sign
|
||||
*/
|
||||
SUCCESS_PAID_FOR_SIGN,
|
||||
|
||||
/**
|
||||
* The message to display when a player has been refunded for breaking a sign
|
||||
*/
|
||||
SUCCESS_REFUNDED,
|
||||
|
||||
/**
|
||||
* The info text used to display all paid signs
|
||||
*/
|
||||
PAID_SIGNS_INFO,
|
||||
|
||||
/**
|
||||
* The format used for displaying a paid sign's name
|
||||
*/
|
||||
PAID_SIGNS_INFO_FORMAT,
|
||||
|
||||
/**
|
||||
* The info text used to display information about a paid sign
|
||||
*/
|
||||
PAID_SIGN_INFO,
|
||||
|
||||
/**
|
||||
* The info text used to display information about a paid sign condition
|
||||
*/
|
||||
PAID_SIGN_CONDITION_INFO,
|
||||
|
||||
/**
|
||||
* The format used for displaying one of a paid sign's conditions
|
||||
*/
|
||||
PAID_SIGN_INFO_CONDITION_FORMAT,
|
||||
|
||||
/**
|
||||
* The message to display for a true boolean value
|
||||
*/
|
||||
BOOLEAN_TRUE,
|
||||
|
||||
/**
|
||||
* The message to display for a false boolean value
|
||||
*/
|
||||
BOOLEAN_FALSE,
|
||||
|
||||
/**
|
||||
* The error to display when a command argument contains an invalid number
|
||||
*/
|
||||
ERROR_INVALID_NUMBER,
|
||||
|
||||
/**
|
||||
* The error to display if a paid sign name duplicate is encountered
|
||||
*/
|
||||
ERROR_NAME_DUPLICATE,
|
||||
|
||||
/**
|
||||
* The error to display if a severe exception occurs
|
||||
*/
|
||||
ERROR_EXCEPTION_OCCURRED,
|
||||
|
||||
/**
|
||||
* The error to display if some input is invalid
|
||||
*/
|
||||
ERROR_INVALID_INPUT,
|
||||
|
||||
/**
|
||||
* The error to display if a specified paid sign is not found
|
||||
*/
|
||||
ERROR_PAID_SIGN_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* The error to display if a paid sign condition is specified, but does not exist
|
||||
*/
|
||||
ERROR_NO_SUCH_CONDITION,
|
||||
|
||||
/**
|
||||
* The error to display if a player cannot pay for a sign matching a paid sign
|
||||
*/
|
||||
ERROR_CANNOT_AFFORD,
|
||||
|
||||
/**
|
||||
* The error to display if an invalid regular expression is provided
|
||||
*/
|
||||
ERROR_INVALID_REGULAR_EXPRESSION,
|
||||
|
||||
/**
|
||||
* The error to display if an invalid property is given to the edit command
|
||||
*/
|
||||
ERROR_PROPERTY_NOT_RECOGNIZED,
|
||||
|
||||
}
|
118
src/main/java/net/knarcraft/paidsigns/formatting/Translator.java
Normal file
118
src/main/java/net/knarcraft/paidsigns/formatting/Translator.java
Normal file
@ -0,0 +1,118 @@
|
||||
package net.knarcraft.paidsigns.formatting;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.utility.FileHelper;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* A tool to get strings translated to the correct language
|
||||
*/
|
||||
public final class Translator {
|
||||
|
||||
private static Map<TranslatableMessage, String> translatedMessages;
|
||||
private static Map<TranslatableMessage, String> backupTranslatedMessages;
|
||||
|
||||
private Translator() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the languages used by this translator
|
||||
*/
|
||||
public static void loadLanguages(String selectedLanguage) {
|
||||
backupTranslatedMessages = loadTranslatedMessages("en");
|
||||
translatedMessages = loadCustomTranslatedMessages(selectedLanguage);
|
||||
if (translatedMessages == null) {
|
||||
translatedMessages = loadTranslatedMessages(selectedLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a translated version of the given translatable message
|
||||
*
|
||||
* @param translatableMessage <p>The message to translate</p>
|
||||
* @return <p>The translated message</p>
|
||||
*/
|
||||
public static String getTranslatedMessage(TranslatableMessage translatableMessage) {
|
||||
if (translatedMessages == null) {
|
||||
return "Translated strings not loaded";
|
||||
}
|
||||
String translatedMessage;
|
||||
if (translatedMessages.containsKey(translatableMessage)) {
|
||||
translatedMessage = translatedMessages.get(translatableMessage);
|
||||
} else if (backupTranslatedMessages.containsKey(translatableMessage)) {
|
||||
translatedMessage = backupTranslatedMessages.get(translatableMessage);
|
||||
} else {
|
||||
translatedMessage = translatableMessage.toString();
|
||||
}
|
||||
return StringFormatter.translateAllColorCodes(translatedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all translated messages for the given language
|
||||
*
|
||||
* @param language <p>The language chosen by the user</p>
|
||||
* @return <p>A mapping of all strings for the given language</p>
|
||||
*/
|
||||
public static Map<TranslatableMessage, String> loadTranslatedMessages(String language) {
|
||||
try {
|
||||
BufferedReader reader = FileHelper.getBufferedReaderForInternalFile("/strings.yml");
|
||||
return loadTranslatableMessages(language, reader);
|
||||
} catch (FileNotFoundException e) {
|
||||
PaidSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to load translated messages");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load translated messages from a custom strings.yml file
|
||||
*
|
||||
* @param language <p>The selected language</p>
|
||||
* @return <p>The loaded translated strings, or null if no custom language file exists</p>
|
||||
*/
|
||||
public static Map<TranslatableMessage, String> loadCustomTranslatedMessages(String language) {
|
||||
File strings = new File(PaidSigns.getInstance().getDataFolder(), "strings.yml");
|
||||
if (!strings.exists()) {
|
||||
PaidSigns.getInstance().getLogger().log(Level.FINEST, "Strings file not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
PaidSigns.getInstance().getLogger().log(Level.WARNING, "Loading custom strings...");
|
||||
return loadTranslatableMessages(language, new BufferedReader(new InputStreamReader(new FileInputStream(strings))));
|
||||
} catch (FileNotFoundException e) {
|
||||
PaidSigns.getInstance().getLogger().log(Level.WARNING, "Unable to load custom messages");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads translatable messages from the given reader
|
||||
*
|
||||
* @param language <p>The selected language</p>
|
||||
* @param reader <p>The buffered reader to read from</p>
|
||||
* @return <p>The loaded translated strings</p>
|
||||
*/
|
||||
private static Map<TranslatableMessage, String> loadTranslatableMessages(String language, BufferedReader reader) {
|
||||
Map<TranslatableMessage, String> translatedMessages = new HashMap<>();
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(reader);
|
||||
|
||||
for (TranslatableMessage message : TranslatableMessage.values()) {
|
||||
String translated = configuration.getString(language + "." + message.toString());
|
||||
if (translated != null) {
|
||||
translatedMessages.put(message, translated);
|
||||
}
|
||||
}
|
||||
return translatedMessages;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package net.knarcraft.paidsigns.listener;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.manager.TrackedSignManager;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
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.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.block.BlockPistonExtendEvent;
|
||||
import org.bukkit.event.block.BlockPistonRetractEvent;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A listener that listens for any tracked signs being broken
|
||||
*/
|
||||
public class SignBreakListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSign(event.getBlock(), true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onExplosion(BlockExplodeEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSigns(event.blockList());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onEntityExplosion(EntityExplodeEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSigns(event.blockList());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPistonPush(BlockPistonExtendEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSigns(event.getBlocks());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPistonPull(BlockPistonRetractEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSigns(event.getBlocks());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onEntityBlockChange(EntityChangeBlockEvent event) {
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
if (event.getEntity() instanceof Player) {
|
||||
return;
|
||||
}
|
||||
removeTrackedSign(event.getBlock(), PaidSigns.getInstance().refundAlways());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all tracked signs from the given blocks
|
||||
*
|
||||
* @param blocks <p>The blocks to search for tracked signs</p>
|
||||
*/
|
||||
private void removeTrackedSigns(List<Block> blocks) {
|
||||
for (Block block : blocks) {
|
||||
removeTrackedSign(block, PaidSigns.getInstance().refundAlways());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to remove any tracked sign at the given block
|
||||
*
|
||||
* @param block <p>The block that might be a sign</p>
|
||||
* @param refund <p>Whether to perform a refund after un-tracking the sign</p>
|
||||
*/
|
||||
private void removeTrackedSign(Block block, boolean refund) {
|
||||
if (block.getState() instanceof Sign) {
|
||||
try {
|
||||
TrackedSignManager.removeTrackedSign(block.getLocation(), refund);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2,68 +2,88 @@ package net.knarcraft.paidsigns.listener;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import net.knarcraft.paidsigns.manager.EconomyManager;
|
||||
import net.knarcraft.paidsigns.manager.PaidSignManager;
|
||||
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.util.List;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A listener for listening to registered paid signs
|
||||
*/
|
||||
public class SignListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@SuppressWarnings("unused")
|
||||
public void onSignChange(SignChangeEvent event) {
|
||||
if (event.isCancelled() || event.getPlayer().hasPermission("paidsigns.paymentexempt")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] lines = event.getLines();
|
||||
PaidSignManager signManager = PaidSigns.getInstance().getSignManager();
|
||||
for (short lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
||||
//Get all "weak" matches (any paid sign with a clean id matching the clean line)
|
||||
List<PaidSign> matchingSigns = signManager.getPaidSigns(PaidSign.getCleanString(lines[lineIndex]), lineIndex);
|
||||
if (matchingSigns.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (testMatchingSigns(lineIndex, lines[lineIndex], matchingSigns, event)) {
|
||||
Map<String, PaidSign> matchingSigns = PaidSigns.getInstance().getSignManager().getAllPaidSigns();
|
||||
for (PaidSign paidSign : matchingSigns.values()) {
|
||||
//If a match is found, just return
|
||||
if (matchSign(paidSign, lines, event)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests all weak matches of paid signs to check if a strong match is found
|
||||
* Checks if the given paid sign matches the given sign lines
|
||||
*
|
||||
* @param lineIndex <p>The index of the currently managed line</p>
|
||||
* @param line <p>The text on the currently managed line</p>
|
||||
* @param matchingSigns <p>The signs that weakly match the </p>
|
||||
* @param event <p>The triggered sign change event</p>
|
||||
* @return <p>True if a match was found and thw work is finished</p>
|
||||
* @param paidSign <p>The paid sign to test against the sign lines</p>
|
||||
* @param lines <p>The lines of a sign</p>
|
||||
* @param event <p>The triggered sign change event to cancel if necessary</p>
|
||||
* @return <p>True if a match was found and actions have been taken</p>
|
||||
*/
|
||||
private boolean testMatchingSigns(short lineIndex, String line, List<PaidSign> matchingSigns, SignChangeEvent event) {
|
||||
for (PaidSign paidSign : matchingSigns) {
|
||||
if (paidSign.matches(lineIndex, line)) {
|
||||
Player player = event.getPlayer();
|
||||
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);
|
||||
}
|
||||
private boolean matchSign(PaidSign paidSign, String[] lines, SignChangeEvent event) {
|
||||
if (paidSign.matches(lines)) {
|
||||
Player player = event.getPlayer();
|
||||
String permission = paidSign.getPermission();
|
||||
//If a match is found, but the player is missing the permission, assume no plugin sign was created
|
||||
if (permission != null && !permission.trim().isEmpty() && !player.hasPermission(permission)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
performPaidSignTransaction(paidSign, player, event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the transaction to pay for the paid sign
|
||||
*
|
||||
* @param paidSign <p>The paid sign a match has been found for</p>
|
||||
* @param player <p>The player that created the sign</p>
|
||||
* @param event <p>The sign change event that caused the sign to be created</p>
|
||||
*/
|
||||
private void performPaidSignTransaction(PaidSign paidSign, Player player, SignChangeEvent event) {
|
||||
double cost = paidSign.getCost();
|
||||
boolean canAfford = EconomyManager.canAfford(player, cost);
|
||||
if (!canAfford) {
|
||||
player.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_CANNOT_AFFORD));
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
String unit = EconomyManager.getCurrency(cost != 1);
|
||||
EconomyManager.withdraw(player, cost);
|
||||
player.sendMessage(String.format(StringFormatter.replacePlaceholders(
|
||||
StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_PAID_FOR_SIGN),
|
||||
new String[]{"{cost}", "{unit}"}, new String[]{"%.2f", "%s"}), cost, unit));
|
||||
try {
|
||||
TrackedSignManager.addTrackedSign(event.getBlock().getLocation(), player.getUniqueId(), cost);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,8 +54,18 @@ public final class EconomyManager {
|
||||
* @param player <p>The player to withdraw money from</p>
|
||||
* @param cost <p>The amount of money to withdraw</p>
|
||||
*/
|
||||
public static void withdraw(Player player, double cost) {
|
||||
public static void withdraw(OfflinePlayer player, double cost) {
|
||||
economy.withdrawPlayer(player, cost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposits a given sum into the given player's account
|
||||
*
|
||||
* @param player <p>The player to deposit money to</p>
|
||||
* @param sum <p>The amount of money to deposit</p>
|
||||
*/
|
||||
public static void deposit(OfflinePlayer player, double sum) {
|
||||
economy.depositPlayer(player, sum);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,32 +2,33 @@ package net.knarcraft.paidsigns.manager;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.PaidSign;
|
||||
import net.knarcraft.paidsigns.container.PaidSignCondition;
|
||||
import net.knarcraft.paidsigns.property.OptionState;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A manager that keeps track of all registered paid signs
|
||||
*/
|
||||
public final class PaidSignManager {
|
||||
|
||||
private final List<PaidSign> paidSigns;
|
||||
private final Map<String, PaidSign> paidSigns;
|
||||
private static final File signsFile = new File(PaidSigns.getInstance().getDataFolder(), "data.yml");
|
||||
private static final String signLineIdSeparator = "-,_,-";
|
||||
|
||||
/**
|
||||
* Instantiate a new paid sign manager
|
||||
*
|
||||
* @param paidSigns <p>The paid signs this manager should manage</p>
|
||||
*/
|
||||
public PaidSignManager(List<PaidSign> paidSigns) {
|
||||
public PaidSignManager(Map<String, PaidSign> paidSigns) {
|
||||
this.paidSigns = paidSigns;
|
||||
}
|
||||
|
||||
@ -38,36 +39,35 @@ public final class PaidSignManager {
|
||||
* @throws IOException <p>If unable to write to the signs file</p>
|
||||
*/
|
||||
public void addPaidSign(PaidSign paidSign) throws IOException {
|
||||
this.paidSigns.add(paidSign);
|
||||
saveSigns(this.paidSigns);
|
||||
this.paidSigns.put(paidSign.getName(), paidSign);
|
||||
saveSigns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a paid sign from this paid sign manager
|
||||
*
|
||||
* @param id <p>The identifier for the paid sign to remove</p>
|
||||
* @param line <p>The line the identifier has to match to be valid</p>
|
||||
* @param name <p>The name of the paid sign to remove</p>
|
||||
* @return <p>True if a sign was removed</p>
|
||||
* @throws IOException <p>If unable to write to the signs file</p>
|
||||
*/
|
||||
public boolean removePaidSign(String id, short line) throws IOException {
|
||||
boolean removed = this.paidSigns.removeIf((sign) -> sign.getId().equals(id) && sign.getLineIndex() == line);
|
||||
public boolean removePaidSign(String name) throws IOException {
|
||||
boolean removed = this.paidSigns.remove(name) != null;
|
||||
if (!removed) {
|
||||
return false;
|
||||
} else {
|
||||
saveSigns();
|
||||
return true;
|
||||
}
|
||||
saveSigns(this.paidSigns);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paid signs that match the given properties
|
||||
* Gets the paid sign with the given name
|
||||
*
|
||||
* @param cleanId <p>The clean id to search for</p>
|
||||
* @param line <p>The line number to search for</p>
|
||||
* @return <p>The paid signs that matched the given properties</p>
|
||||
* @param name <p>The paid sign with the given name</p>
|
||||
* @return <p>The paid sign with the given name, or null if it does not exist</p>
|
||||
*/
|
||||
public List<PaidSign> getPaidSigns(String cleanId, short line) {
|
||||
return filterPaidSigns(filterPaidSigns(paidSigns, line), cleanId);
|
||||
public PaidSign getPaidSign(String name) {
|
||||
return paidSigns.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,19 +75,8 @@ public final class PaidSignManager {
|
||||
*
|
||||
* @return <p>All registered paid signs</p>
|
||||
*/
|
||||
public List<PaidSign> getAllPaidSigns() {
|
||||
return new ArrayList<>(paidSigns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of paid signs to match the given line number
|
||||
*
|
||||
* @param paidSigns <p>The list of paid signs to start with</p>
|
||||
* @param line <p>The line number to filter by</p>
|
||||
* @return <p>The filtered list of paid signs</p>
|
||||
*/
|
||||
private static List<PaidSign> filterPaidSigns(List<PaidSign> paidSigns, short line) {
|
||||
return filterPaidSigns(paidSigns, (paidSign) -> paidSign.getLineIndex() == line);
|
||||
public Map<String, PaidSign> getAllPaidSigns() {
|
||||
return new HashMap<>(paidSigns);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,66 +84,105 @@ public final class PaidSignManager {
|
||||
*
|
||||
* @return <p>The loaded paid signs</p>
|
||||
*/
|
||||
public static List<PaidSign> loadSigns() {
|
||||
public static Map<String, PaidSign> loadSigns() {
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
|
||||
ConfigurationSection signSection = configuration.getConfigurationSection("paidSigns");
|
||||
if (signSection == null) {
|
||||
PaidSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in data.yml");
|
||||
return new ArrayList<>();
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
List<PaidSign> paidSigns = new ArrayList<>();
|
||||
for (String combinedId : signSection.getKeys(false)) {
|
||||
String[] idParts = combinedId.split(signLineIdSeparator);
|
||||
short lineNumber = Short.parseShort(idParts[0]);
|
||||
String id = idParts[1];
|
||||
double cost = signSection.getDouble(combinedId + ".cost");
|
||||
OptionState ignoreCase = OptionState.getFromBoolean(signSection.getBoolean(combinedId + ".ignoreCase"));
|
||||
OptionState ignoreColor = OptionState.getFromBoolean(signSection.getBoolean(combinedId + ".ignoreColor"));
|
||||
paidSigns.add(new PaidSign(id, lineNumber, cost, ignoreCase, ignoreColor));
|
||||
Map<String, PaidSign> paidSigns = new HashMap<>();
|
||||
for (String name : signSection.getKeys(false)) {
|
||||
double cost = signSection.getDouble(name + ".cost");
|
||||
String permission = signSection.getString(name + ".permission");
|
||||
OptionState ignoreCase = OptionState.getFromBoolean(signSection.getBoolean(name + ".ignoreCase"));
|
||||
OptionState ignoreColor = OptionState.getFromBoolean(signSection.getBoolean(name + ".ignoreColor"));
|
||||
boolean matchAnyCondition = signSection.getBoolean(name + ".matchAnyCondition");
|
||||
PaidSign sign = new PaidSign(name, cost, permission, ignoreCase, ignoreColor, matchAnyCondition);
|
||||
loadConditions(signSection, sign);
|
||||
paidSigns.put(name, sign);
|
||||
}
|
||||
return paidSigns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all signs registered to this paid sign manager
|
||||
*
|
||||
* @throws IOException <p>If unable to write to the signs file</p>
|
||||
*/
|
||||
public void saveSigns() throws IOException {
|
||||
saveSigns(this.paidSigns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given paid signs to the signs file
|
||||
*
|
||||
* @param signs <p>The signs to save</p>
|
||||
* @throws IOException <p>If unable to write to the signs file</p>
|
||||
*/
|
||||
public static void saveSigns(List<PaidSign> signs) throws IOException {
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
|
||||
ConfigurationSection signSection = configuration.createSection("paidSigns");
|
||||
public static void saveSigns(Map<String, PaidSign> signs) throws IOException {
|
||||
try {
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
|
||||
ConfigurationSection signSection = configuration.createSection("paidSigns");
|
||||
|
||||
for (PaidSign sign : signs) {
|
||||
String signId = sign.getLineIndex() + signLineIdSeparator + sign.getId();
|
||||
signSection.set(signId + ".cost", sign.getCost());
|
||||
signSection.set(signId + ".ignoreCase", sign.getIgnoreCase());
|
||||
signSection.set(signId + ".ignoreColor", sign.getIgnoreColor());
|
||||
for (PaidSign sign : signs.values()) {
|
||||
saveSign(signSection, sign);
|
||||
}
|
||||
configuration.save(signsFile);
|
||||
} catch (IOException exception) {
|
||||
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(exception.getStackTrace()));
|
||||
throw exception;
|
||||
}
|
||||
configuration.save(signsFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of paid signs to match the given clean id
|
||||
* Saves the given sign to the given configuration section
|
||||
*
|
||||
* @param paidSigns <p>The list of paid signs to start with</p>
|
||||
* @param cleanId <p>The clean id to filter by</p>
|
||||
* @return <p>The filtered list of paid signs</p>
|
||||
* @param signSection <p>The configuration section to save the sign to</p>
|
||||
* @param sign <p>The sign to save</p>
|
||||
*/
|
||||
private static List<PaidSign> filterPaidSigns(List<PaidSign> paidSigns, String cleanId) {
|
||||
return filterPaidSigns(paidSigns, (paidSign) -> paidSign.getCleanId().equals(cleanId));
|
||||
private static void saveSign(ConfigurationSection signSection, PaidSign sign) {
|
||||
String name = sign.getName();
|
||||
signSection.set(name + ".cost", sign.getCost());
|
||||
signSection.set(name + ".permission", sign.getPermission());
|
||||
signSection.set(name + ".ignoreCase", sign.getIgnoreCase());
|
||||
signSection.set(name + ".ignoreColor", sign.getIgnoreColor());
|
||||
signSection.set(name + ".matchAnyCondition", sign.matchAnyCondition());
|
||||
ConfigurationSection conditionsSection = signSection.createSection(name + ".conditions");
|
||||
Map<Short, PaidSignCondition> signConditions = sign.getConditions();
|
||||
for (short lineIndex : signConditions.keySet()) {
|
||||
PaidSignCondition condition = signConditions.get(lineIndex);
|
||||
conditionsSection.set(lineIndex + ".stringToMatch", condition.getStringToMatch());
|
||||
conditionsSection.set(lineIndex + ".executeRegEx", condition.executeRegex());
|
||||
conditionsSection.set(lineIndex + ".ignoreCase", condition.ignoreCase());
|
||||
conditionsSection.set(lineIndex + ".ignoreColor", condition.ignoreColor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of paid signs using the given predicate
|
||||
* Loads any saved paid sign conditions and applies them to the given sign
|
||||
*
|
||||
* @param paidSigns <p>The list of paid signs to start with</p>
|
||||
* @param predicate <p>The predicate used to filter paid signs</p>
|
||||
* @return <p>The filtered list of paid signs</p>
|
||||
* @param signSection <p>The configuration section containing sign information</p>
|
||||
* @param sign <p>The sign to load conditions for</p>
|
||||
*/
|
||||
private static List<PaidSign> filterPaidSigns(List<PaidSign> paidSigns, Predicate<PaidSign> predicate) {
|
||||
return new ArrayList<>(paidSigns).stream().filter(predicate).toList();
|
||||
private static void loadConditions(ConfigurationSection signSection, PaidSign sign) {
|
||||
ConfigurationSection conditionSection = signSection.getConfigurationSection(sign.getName() + ".conditions");
|
||||
if (conditionSection != null) {
|
||||
for (String lineIndex : conditionSection.getKeys(false)) {
|
||||
short lineNumber = Short.parseShort(lineIndex);
|
||||
String stringToMatch = conditionSection.getString(lineIndex + ".stringToMatch");
|
||||
boolean executeRegEx = conditionSection.getBoolean(lineIndex + ".executeRegEx");
|
||||
boolean ignoreConditionCase = conditionSection.getBoolean(lineIndex + ".ignoreCase");
|
||||
boolean ignoreConditionColor = conditionSection.getBoolean(lineIndex + ".ignoreColor");
|
||||
sign.addCondition(lineNumber, stringToMatch, executeRegEx,
|
||||
OptionState.getFromBoolean(ignoreConditionCase),
|
||||
OptionState.getFromBoolean(ignoreConditionColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,150 @@
|
||||
package net.knarcraft.paidsigns.manager;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import net.knarcraft.paidsigns.container.TrackedSign;
|
||||
import net.knarcraft.paidsigns.formatting.StringFormatter;
|
||||
import net.knarcraft.paidsigns.formatting.TranslatableMessage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
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 final class TrackedSignManager {
|
||||
|
||||
private static Map<Location, TrackedSign> trackedSigns = new HashMap<>();
|
||||
private static final File signsFile = new File(PaidSigns.getInstance().getDataFolder(), "data.yml");
|
||||
|
||||
private TrackedSignManager() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tracked sign to the manager
|
||||
*
|
||||
* @param signLocation <p>The location the sign was created at</p>
|
||||
* @param playerId <p>The unique id of the player that created the sign</p>
|
||||
* @throws IOException <p>If unable to save the tracked signs</p>
|
||||
*/
|
||||
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 signLocation <p>The location the sign was removed from</p>
|
||||
* @param refund <p>Whether to perform a refund after un-tracking the sign</p>
|
||||
* @throws IOException <p>If unable to save the tracked signs</p>
|
||||
*/
|
||||
public static void removeTrackedSign(Location signLocation, boolean refund) throws IOException {
|
||||
if (!trackedSigns.containsKey(signLocation)) {
|
||||
return;
|
||||
}
|
||||
TrackedSign trackedSign = trackedSigns.get(signLocation);
|
||||
trackedSigns.remove(signLocation);
|
||||
saveTrackedSigns();
|
||||
if (!PaidSigns.getInstance().areRefundsEnabled() || !refund) {
|
||||
return;
|
||||
}
|
||||
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(trackedSign.getPlayerId());
|
||||
double refundSum = trackedSign.getCost() / 100 * PaidSigns.getInstance().getRefundPercentage();
|
||||
EconomyManager.deposit(offlinePlayer, refundSum);
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
player.sendMessage(String.format(StringFormatter.replacePlaceholders(
|
||||
StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_REFUNDED),
|
||||
new String[]{"{cost}", "{unit}"}, new String[]{"%.2f", "%s"}), refundSum,
|
||||
EconomyManager.getCurrency(refundSum != 1)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, "Tracked 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 signSection <p>The configuration section containing signs</p>
|
||||
* @param key <p>The sign key which is also the sign's location</p>
|
||||
* @throws InvalidConfigurationException <p>If unable to load the sign</p>
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
//Prevent destroyed signs from being tracked indefinitely
|
||||
if (!(signLocation.getBlock().getState() instanceof Sign)) {
|
||||
PaidSigns.getInstance().getLogger().log(Level.WARNING, "The sign at " + signLocation + " no longer " +
|
||||
"exists. Removing from sign tracker.");
|
||||
return;
|
||||
}
|
||||
|
||||
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 IOException <p>If unable to write to the data file</p>
|
||||
*/
|
||||
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().toString());
|
||||
}
|
||||
configuration.save(signsFile);
|
||||
}
|
||||
|
||||
}
|
@ -23,14 +23,15 @@ public enum OptionState {
|
||||
/**
|
||||
* Gets the boolean value of the given option state if it's boolean compatible
|
||||
*
|
||||
* @param optionState <p>The option state to get the boolean from</p>
|
||||
* @return <p>The boolean value, or an illegal argument exception if called on DEFAULT</p>
|
||||
* @param optionState <p>The option state to get the boolean from</p>
|
||||
* @param defaultValue <p>The default value to use if the option state is DEFAULT</p>
|
||||
* @return <p>The boolean value</p>
|
||||
*/
|
||||
public static boolean getBooleanValue(OptionState optionState) {
|
||||
public static boolean getBooleanValue(OptionState optionState, boolean defaultValue) {
|
||||
return switch (optionState) {
|
||||
case TRUE -> true;
|
||||
case FALSE -> false;
|
||||
case DEFAULT -> throw new IllegalArgumentException("No boolean value available for DEFAULT");
|
||||
case DEFAULT -> defaultValue;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
package net.knarcraft.paidsigns.property;
|
||||
|
||||
/**
|
||||
* A representation of a paid sign condition's editable properties
|
||||
*/
|
||||
public enum PaidSignConditionProperty {
|
||||
|
||||
/**
|
||||
* The string used to trigger the paid sign condition
|
||||
*/
|
||||
STRING_TO_MATCH("stringToMatch"),
|
||||
|
||||
/**
|
||||
* Whether to execute the match string as a regular expression
|
||||
*/
|
||||
EXECUTE_REG_EX("executeRegEx"),
|
||||
|
||||
/**
|
||||
* Whether to ignore case for the sign condition
|
||||
*/
|
||||
IGNORE_CASE("ignoreCase"),
|
||||
|
||||
/**
|
||||
* Whether to ignore color for the sign condition
|
||||
*/
|
||||
IGNORE_COLOR("ignoreColor");
|
||||
|
||||
private final String stringRepresentation;
|
||||
|
||||
/**
|
||||
* Instantiates a new paid sign condition property
|
||||
*
|
||||
* @param stringRepresentation <p>The string representation of the paid sign condition property</p>
|
||||
*/
|
||||
PaidSignConditionProperty(String stringRepresentation) {
|
||||
this.stringRepresentation = stringRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of this paid sign condition property
|
||||
*
|
||||
* @return <p>The string representation of this paid sign condition property</p>
|
||||
*/
|
||||
public String getStringRepresentation() {
|
||||
return this.stringRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paid sign property matching the given string
|
||||
*
|
||||
* @param propertyString <p>The string representing a paid sign condition property</p>
|
||||
* @return <p>The matching paid sign condition property, or null if no such property exists</p>
|
||||
*/
|
||||
public static PaidSignConditionProperty getFromString(String propertyString) {
|
||||
for (PaidSignConditionProperty paidSignProperty : PaidSignConditionProperty.values()) {
|
||||
if (paidSignProperty.getStringRepresentation().equalsIgnoreCase(propertyString)) {
|
||||
return paidSignProperty;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package net.knarcraft.paidsigns.property;
|
||||
|
||||
/**
|
||||
* A representation of a paid sign's editable properties
|
||||
*/
|
||||
public enum PaidSignProperty {
|
||||
|
||||
/**
|
||||
* The name of a paid sign
|
||||
*/
|
||||
NAME("name"),
|
||||
|
||||
/**
|
||||
* The cost of creating a sign matching the paid sign
|
||||
*/
|
||||
COST("cost"),
|
||||
|
||||
/**
|
||||
* The permission required to create the plugin sign matching the paid sign
|
||||
*/
|
||||
PERMISSION("permission"),
|
||||
|
||||
/**
|
||||
* Whether to ignore case for any sign conditions added to the sign
|
||||
*/
|
||||
IGNORE_CASE("ignoreCase"),
|
||||
|
||||
/**
|
||||
* Whether to ignore color for any sign conditions added to the sign
|
||||
*/
|
||||
IGNORE_COLOR("ignoreColor"),
|
||||
|
||||
/**
|
||||
* Whether to treat a single condition match as a full match
|
||||
*/
|
||||
MATCH_ANY_CONDITION("matchAnyCondition");
|
||||
|
||||
private final String stringRepresentation;
|
||||
|
||||
/**
|
||||
* Instantiates a new paid sign property
|
||||
*
|
||||
* @param stringRepresentation <p>The string representation of the paid sign property</p>
|
||||
*/
|
||||
PaidSignProperty(String stringRepresentation) {
|
||||
this.stringRepresentation = stringRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string representation of this paid sign property
|
||||
*
|
||||
* @return <p>The string representation of this paid sign property</p>
|
||||
*/
|
||||
public String getStringRepresentation() {
|
||||
return this.stringRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paid sign property matching the given string
|
||||
*
|
||||
* @param propertyString <p>The string representing a paid sign property</p>
|
||||
* @return <p>The matching paid sign property, or null if no such property exists</p>
|
||||
*/
|
||||
public static PaidSignProperty getFromString(String propertyString) {
|
||||
for (PaidSignProperty paidSignProperty : PaidSignProperty.values()) {
|
||||
if (paidSignProperty.getStringRepresentation().equalsIgnoreCase(propertyString)) {
|
||||
return paidSignProperty;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package net.knarcraft.paidsigns.utility;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* A helper class for dealing with files
|
||||
*/
|
||||
public final class FileHelper {
|
||||
|
||||
private FileHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered reader for
|
||||
*
|
||||
* @return <p>A buffered read for reading the file</p>
|
||||
* @throws FileNotFoundException <p>If unable to get an input stream for the given file</p>
|
||||
*/
|
||||
public static BufferedReader getBufferedReaderForInternalFile(String file) throws FileNotFoundException {
|
||||
InputStream inputStream = FileHelper.class.getResourceAsStream(file);
|
||||
if (inputStream == null) {
|
||||
throw new FileNotFoundException("Unable to read the given file");
|
||||
}
|
||||
return new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package net.knarcraft.paidsigns.utility;
|
||||
|
||||
import net.knarcraft.paidsigns.PaidSigns;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* A helper class for providing common tab complete options
|
||||
*/
|
||||
public final class TabCompleteHelper {
|
||||
|
||||
private static List<String> plugins;
|
||||
private static Map<String, List<String>> permissions;
|
||||
|
||||
private TabCompleteHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds tab complete values that match the start of the typed text
|
||||
*
|
||||
* @param values <p>The values to filter</p>
|
||||
* @param typedText <p>The text the player has started typing</p>
|
||||
* @return <p>The given string values that start with the player's typed text</p>
|
||||
*/
|
||||
public static List<String> filterMatchingStartsWith(List<String> values, String typedText) {
|
||||
List<String> configValues = new ArrayList<>();
|
||||
for (String value : values) {
|
||||
if (value.toLowerCase().startsWith(typedText.toLowerCase())) {
|
||||
configValues.add(value);
|
||||
}
|
||||
}
|
||||
return configValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available boolean values for tab completion
|
||||
*
|
||||
* @return <p>The available boolean values</p>
|
||||
*/
|
||||
public static List<String> getBooleans() {
|
||||
List<String> booleans = new ArrayList<>();
|
||||
booleans.add("true");
|
||||
booleans.add("false");
|
||||
return booleans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available option states for tab completion
|
||||
*
|
||||
* @return <p>The available option states</p>
|
||||
*/
|
||||
public static List<String> getOptionStates() {
|
||||
List<String> optionStates = getBooleans();
|
||||
optionStates.add("default");
|
||||
return optionStates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all registered paid signs
|
||||
*
|
||||
* @return <p>The names of all registered paid signs</p>
|
||||
*/
|
||||
public static List<String> getPaidSignNames() {
|
||||
Set<String> paidSignNames = PaidSigns.getInstance().getSignManager().getAllPaidSigns().keySet();
|
||||
List<String> quotedNames = new ArrayList<>(paidSignNames.size());
|
||||
for (String paidSignName : paidSignNames) {
|
||||
quotedNames.add("\"" + paidSignName + "\"");
|
||||
}
|
||||
return quotedNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the choices for lines on a sign
|
||||
*
|
||||
* @return <p>All the line indices of a sign</p>
|
||||
*/
|
||||
public static List<String> getSignLines() {
|
||||
List<String> lines = new ArrayList<>();
|
||||
for (int i = 1; i < 5; i++) {
|
||||
lines.add(String.valueOf(i));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets some valid costs as example values
|
||||
*
|
||||
* @return <p>Some valid costs</p>
|
||||
*/
|
||||
public static List<String> getCosts() {
|
||||
List<String> costs = new ArrayList<>();
|
||||
costs.add("1");
|
||||
costs.add("5");
|
||||
costs.add("10");
|
||||
costs.add("15");
|
||||
return costs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets some example paid sign names for auto-completion
|
||||
*
|
||||
* @return <p>Some example paid sign names</p>
|
||||
*/
|
||||
public static List<String> getExamplePaidSignNames() {
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add("sign1");
|
||||
names.add("\"lift up sign\"");
|
||||
names.add("\"lift down sign\"");
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets some example condition matching strings for tab completion
|
||||
*
|
||||
* @return <p>Some example "stringToMatch" values</p>
|
||||
*/
|
||||
public static List<String> getExampleConditionStrings() {
|
||||
List<String> conditionStrings = new ArrayList<>();
|
||||
conditionStrings.add("[Gate]");
|
||||
conditionStrings.add("\"[Lift Up]\"");
|
||||
conditionStrings.add("\"[Lift Down]\"");
|
||||
return conditionStrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tab complete value for the permission typed
|
||||
*
|
||||
* @param typedNode <p>The full permission node typed by the player</p>
|
||||
* @return <p>All known valid auto-complete options</p>
|
||||
*/
|
||||
public static List<String> tabCompletePermission(String typedNode) {
|
||||
if (plugins == null) {
|
||||
loadAvailablePermissions();
|
||||
}
|
||||
List<String> output;
|
||||
if (typedNode.contains(".")) {
|
||||
List<String> matchingPermissions = permissions.get(typedNode.substring(0, typedNode.lastIndexOf(".")));
|
||||
if (matchingPermissions == null) {
|
||||
output = new ArrayList<>();
|
||||
} else {
|
||||
//Filter by the typed text
|
||||
output = TabCompleteHelper.filterMatchingStartsWith(matchingPermissions, typedNode);
|
||||
}
|
||||
} else {
|
||||
output = plugins;
|
||||
}
|
||||
|
||||
//Add previous permissions in the comma-separated lists as a prefix
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all permissions available from bukkit plugins
|
||||
*/
|
||||
private static void loadAvailablePermissions() {
|
||||
plugins = new ArrayList<>();
|
||||
permissions = new HashMap<>();
|
||||
|
||||
for (Permission permission : Bukkit.getPluginManager().getPermissions()) {
|
||||
loadPermission(permission.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a given permission into the proper lists and maps
|
||||
*
|
||||
* @param permissionName <p>The permission to load</p>
|
||||
*/
|
||||
private static void loadPermission(String permissionName) {
|
||||
String[] permissionParts = permissionName.split("\\.");
|
||||
if (permissionParts.length == 1 && !plugins.contains(permissionParts[0])) {
|
||||
plugins.add(permissionParts[0]);
|
||||
} else if (permissionParts.length > 1) {
|
||||
StringJoiner pathJoiner = new StringJoiner(".");
|
||||
for (int j = 0; j < permissionParts.length - 1; j++) {
|
||||
pathJoiner.add(permissionParts[j]);
|
||||
}
|
||||
String path = pathJoiner.toString();
|
||||
List<String> permissionList = permissions.computeIfAbsent(path, k -> new ArrayList<>());
|
||||
permissionList.add(permissionName);
|
||||
|
||||
loadPermission(path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,15 +6,30 @@ import java.util.List;
|
||||
/**
|
||||
* A tokenizer for being able to support quotes in commands
|
||||
*/
|
||||
public class Tokenizer {
|
||||
public final class Tokenizer {
|
||||
|
||||
private Tokenizer() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a string
|
||||
*
|
||||
* @param input <p>A string.</p>
|
||||
* @return <p>A list of tokens.</p>
|
||||
* @param input <p>A string</p>
|
||||
* @return <p>A list of tokens</p>
|
||||
*/
|
||||
public static List<String> tokenize(String input) {
|
||||
return tokenize(input, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenizes a string
|
||||
*
|
||||
* @param input <p>A string</p>
|
||||
* @param allowEmptyQuotes <p>Whether to treat "" as a token</p>
|
||||
* @return <p>A list of tokens</p>
|
||||
*/
|
||||
public static List<String> tokenize(String input, boolean allowEmptyQuotes) {
|
||||
List<String> tokens = new ArrayList<>();
|
||||
boolean startedQuote = false;
|
||||
StringBuilder currentToken = new StringBuilder();
|
||||
@ -29,7 +44,7 @@ public class Tokenizer {
|
||||
case '"':
|
||||
if (startedQuote) {
|
||||
//This quote signifies the end of the argument
|
||||
if (isNotEmpty(currentToken)) {
|
||||
if (allowEmptyQuotes || isNotEmpty(currentToken)) {
|
||||
tokens.add(currentToken.toString());
|
||||
currentToken = new StringBuilder();
|
||||
}
|
||||
|
@ -1,8 +1,23 @@
|
||||
# The currently enabled language. More languages can be added to the language file
|
||||
language: en
|
||||
|
||||
# Whether to ignore the case (lowercase/uppercase) of the paid sign text. The option can be set on a per-sign basis, but
|
||||
# this value is used if not specified. The correct value depends on whether the plugin signs it should match are case-sensitive or not.
|
||||
# this value is used if not specified. The correct value depends on whether the plugin signs it should match are
|
||||
# case-sensitive or not.
|
||||
ignoreCase: true
|
||||
|
||||
# Whether to ignore any color or formatting applied to the text when trying to match a paid sign's text. The option can
|
||||
# be set on a per-sign basis, but this value is used if not specified. The correct value depends on whether the plugin
|
||||
# signs it should match allow coloring or not.
|
||||
ignoreColor: false
|
||||
ignoreColor: false
|
||||
|
||||
# Whether to enable refunds to the sign creator when a sign detected as a paid sign is broken (payment will always go
|
||||
# to the original creator)
|
||||
refundsEnabled: true
|
||||
|
||||
# The percentage of the paid sign cost to refund (0-100)
|
||||
refundPercentage: 100
|
||||
|
||||
# Whether to refund when signs that players have paid for are broken by anything. This includes tnt, creepers, pistons
|
||||
# and similar
|
||||
refundAlways: false
|
@ -6,17 +6,47 @@ prefix: PaidSigns
|
||||
depend: [ Vault ]
|
||||
authors: [ EpicKnarvik97 ]
|
||||
description: Add costs for creating plugin signs
|
||||
website: https://git.knarcraft.net
|
||||
website: https://git.knarcraft.net/EpicKnarvik97/PaidSigns
|
||||
commands:
|
||||
addpaidsign:
|
||||
aliases:
|
||||
- aps
|
||||
description: Used to add a new paid sign
|
||||
usage: /<command> <id (the text to look for)> <line> <cost> [ignore case] [ignore color]
|
||||
permission: paidsigns.add
|
||||
usage: /<command> <name> <cost> [permission] [ignore case] [ignore color] [match any condition]
|
||||
permission: paidsigns.manage
|
||||
addpaidsigncondition:
|
||||
aliases:
|
||||
- apsc
|
||||
description: Used to add a new match condition for a paid sign
|
||||
usage: /<command> <name (of a paid sign)> <line number> <string to match> [executeRegEx] [ignoreCase] [ignoreColor]
|
||||
permission: paidsigns.manage
|
||||
listpaidsigns:
|
||||
aliases:
|
||||
- lps
|
||||
description: Lists all previously added paid signs
|
||||
usage: /<command> [sign name] [line number]
|
||||
permission: paidsigns.manage
|
||||
editpaidsign:
|
||||
aliases:
|
||||
- eps
|
||||
description: Edits a property of a paid sign or a paid sign condition
|
||||
usage: /<command> <sign name> <property>/<line number> [new value]/<property> [new value]
|
||||
permission: paidsigns.manage
|
||||
removepaidsigncondition:
|
||||
aliases:
|
||||
- rpsc
|
||||
description: Used to remove a match condition from a paid sign
|
||||
usage: /<command> <name (of a paid sign)> <line number>
|
||||
permission: paidsigns.manage
|
||||
removepaidsign:
|
||||
aliases:
|
||||
- rps
|
||||
description: Used to remove a paid sign
|
||||
usage: /<command> <id (the text to look for)> <line>
|
||||
permission: paidsigns.remove
|
||||
usage: /<command> <name (of a paid sign)>
|
||||
permission: paidsigns.manage
|
||||
reload:
|
||||
aliases:
|
||||
- r
|
||||
description: Reloads paid signs from disk
|
||||
usage: /<command>
|
||||
permision: paidsigns.reload
|
||||
@ -28,7 +58,7 @@ permissions:
|
||||
paidsigns.create: true
|
||||
paidsigns.paymentexempt: true
|
||||
paidsigns.reload: true
|
||||
paidsigns.add:
|
||||
paidsigns.manage:
|
||||
description: Grants the permission to add/remove a paid sign
|
||||
default: false
|
||||
paidsigns.reload:
|
||||
|
27
src/main/resources/strings.yml
Normal file
27
src/main/resources/strings.yml
Normal file
@ -0,0 +1,27 @@
|
||||
en:
|
||||
PREFIX: "[PaidSigns]"
|
||||
SUCCESS_ADDED_PAID_SIGN: "&bSuccessfully added new paid sign"
|
||||
SUCCESS_ADDED_PAID_SIGN_CONDITION: "&bSuccessfully added new paid sign condition"
|
||||
SUCCESS_UPDATED_PAID_SIGN: "&bSuccessfully updated the paid sign property"
|
||||
SUCCESS_UPDATED_PAID_SIGN_CONDITION: "&bSuccessfully updated the paid sign condition property"
|
||||
SUCCESS_REMOVED_PAID_SIGN: "&bSuccessfully removed paid sign"
|
||||
SUCCESS_REMOVED_CONDITION: "&bSuccessfully removed paid sign condition"
|
||||
SUCCESS_RELOADED: "&bSuccessfully reloaded configuration"
|
||||
SUCCESS_PAID_FOR_SIGN: "&bYou paid &3{cost} {unit} &bto create the sign"
|
||||
SUCCESS_REFUNDED: "&bYou were refunded &3{cost} {unit} &bfor your broken sign"
|
||||
PAID_SIGNS_INFO: "&f---&3Paid signs&f---{signs}\n&f-----------"
|
||||
PAID_SIGNS_INFO_FORMAT: "\n&f| &3{name}"
|
||||
PAID_SIGN_INFO: "&f---&3Paid sign&f---\n&f| &bName: &3{name}\n&f| &bCost: &3{cost}\n&f| &bPermission: &3{permission}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n&f| &bMatch any condition: &3{any}\n&f| &bSign conditions: &3{conditions}\n&f---------------"
|
||||
PAID_SIGN_INFO_CONDITION_FORMAT: "\n&f| &b{line}: &3{condition}"
|
||||
PAID_SIGN_CONDITION_INFO: "&f---&3Paid sign condition&f---\n&f| &bPaid sign name: &3{name}\n&f| &bCondition line: &3{line}\n&f| &bMatch string: &3{match}\n&f| &bExecute RegEx: &3{regex}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n&f---------------"
|
||||
BOOLEAN_TRUE: "&2true"
|
||||
BOOLEAN_FALSE: "&4false"
|
||||
ERROR_INVALID_NUMBER: "&bYou provided an invalid number"
|
||||
ERROR_NAME_DUPLICATE: "&bA paid sign with the same name already exists"
|
||||
ERROR_EXCEPTION_OCCURRED: "&bAn exception occurred. Please notify the server administrator or check the server log."
|
||||
ERROR_INVALID_INPUT: "&bInvalid input: {input}"
|
||||
ERROR_PAID_SIGN_NOT_FOUND: "&bNo such paid sign exists"
|
||||
ERROR_NO_SUCH_CONDITION: "&bThe paid sign you specified has no condition for line {line}"
|
||||
ERROR_CANNOT_AFFORD: "&bYou cannot afford to create this sign"
|
||||
ERROR_INVALID_REGULAR_EXPRESSION: "&bThe provided regular expression is invalid"
|
||||
ERROR_PROPERTY_NOT_RECOGNIZED: "&bThe property you tried to change was not recognized"
|
Reference in New Issue
Block a user