diff --git a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java index 19260aa..0f6dccb 100644 --- a/src/main/java/net/knarcraft/stargate/command/CommandConfig.java +++ b/src/main/java/net/knarcraft/stargate/command/CommandConfig.java @@ -9,6 +9,7 @@ import net.knarcraft.stargate.portal.PortalRegistry; import net.knarcraft.stargate.portal.PortalSignDrawer; import net.md_5.bungee.api.ChatColor; import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -16,6 +17,9 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + /** * This command represents the config command for changing config values */ @@ -37,7 +41,11 @@ public class CommandConfig implements CommandExecutor { return false; } if (args.length > 1) { - updateConfigValue(selectedOption, commandSender, args[1]); + if (selectedOption.getDataType() == OptionDataType.STRING_LIST) { + updateListConfigValue(selectedOption, commandSender, args); + } else { + updateConfigValue(selectedOption, commandSender, args[1]); + } } else { //Display info and the current value of the given config value printConfigOptionValue(commandSender, selectedOption); @@ -72,14 +80,7 @@ public class CommandConfig implements CommandExecutor { //Store the config values, accounting for the data type switch (selectedOption.getDataType()) { - case BOOLEAN -> { - boolean newValue = Boolean.parseBoolean(value); - if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) { - Stargate.getStargateConfig().startStopBungeeListener(newValue); - } - Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, newValue); - configuration.set(selectedOption.getConfigNode(), newValue); - } + case BOOLEAN -> updateBooleanConfigValue(selectedOption, value, configuration); case INTEGER -> { Integer intValue = getInteger(commandSender, selectedOption, value); if (intValue == null) { @@ -90,35 +91,158 @@ public class CommandConfig implements CommandExecutor { } } case STRING -> { - if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER || - selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) { - if (value.contains("../") || value.contains("..\\")) { - commandSender.sendMessage(ChatColor.RED + "Path traversal characters cannot be used"); - return; - } - } - if (ConfigTag.COLOR.isTagged(selectedOption)) { - if (!registerColor(selectedOption, value, commandSender)) { - return; - } - } - if (selectedOption == ConfigOption.LANGUAGE) { - Stargate.getStargateConfig().getLanguageLoader().setChosenLanguage(value); - } - Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value); + updateStringConfigValue(selectedOption, commandSender, value); configuration.set(selectedOption.getConfigNode(), value); } - case STRING_LIST -> { - if (selectedOption == ConfigOption.PER_SIGN_COLORS) { - commandSender.sendMessage(ChatColor.RED + value); - } - } default -> { Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value); configuration.set(selectedOption.getConfigNode(), value); } } + saveAndReload(selectedOption, commandSender); + } + + /** + * Updates a boolean config value + * + * @param selectedOption

The option which should be updated

+ * @param value

The new value of the config option

+ * @param configuration

The configuration file to save to

+ */ + private void updateBooleanConfigValue(ConfigOption selectedOption, String value, FileConfiguration configuration) { + boolean newValue = Boolean.parseBoolean(value); + if (selectedOption == ConfigOption.ENABLE_BUNGEE && newValue != Stargate.getGateConfig().enableBungee()) { + Stargate.getStargateConfig().startStopBungeeListener(newValue); + } + Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, newValue); + configuration.set(selectedOption.getConfigNode(), newValue); + } + + /** + * Updates a string config value + * + * @param selectedOption

The option which should be updated

+ * @param commandSender

The command sender that changed the value

+ * @param value

The new value of the config option

+ */ + private void updateStringConfigValue(ConfigOption selectedOption, CommandSender commandSender, String value) { + if (selectedOption == ConfigOption.GATE_FOLDER || selectedOption == ConfigOption.PORTAL_FOLDER || + selectedOption == ConfigOption.DEFAULT_GATE_NETWORK) { + if (value.contains("../") || value.contains("..\\")) { + commandSender.sendMessage(ChatColor.RED + "Path traversal characters cannot be used"); + return; + } + } + if (ConfigTag.COLOR.isTagged(selectedOption)) { + if (!registerColor(selectedOption, value, commandSender)) { + return; + } + } + if (selectedOption == ConfigOption.LANGUAGE) { + Stargate.getStargateConfig().getLanguageLoader().setChosenLanguage(value); + } + Stargate.getStargateConfig().getConfigOptionsReference().put(selectedOption, value); + } + + /** + * Updates a config value + * + * @param selectedOption

The option which should be updated

+ * @param commandSender

The command sender that changed the value

+ * @param arguments

The arguments for the new config option

+ */ + private void updateListConfigValue(ConfigOption selectedOption, CommandSender commandSender, String[] arguments) { + FileConfiguration configuration = Stargate.getInstance().getConfig(); + + if (selectedOption == ConfigOption.PER_SIGN_COLORS) { + if (arguments.length < 4) { + Stargate.getMessageSender().sendErrorMessage(commandSender, "Usage: /sg config perSignColors " + + " "); + return; + } + + String colorString = parsePerSignColorInput(commandSender, arguments); + if (colorString == null) { + return; + } + + //Update the per-sign colors according to input + updatePerSignColors(arguments[1], colorString, configuration); + } + + saveAndReload(selectedOption, commandSender); + } + + /** + * Parses the input given for changing the per-color string + * + * @param commandSender

The command sender that triggered the command

+ * @param arguments

The arguments given by the user

+ * @return

The per-sign color string to update with, or null if the input was invalid

+ */ + private String parsePerSignColorInput(CommandSender commandSender, String[] arguments) { + //Make sure the sign type is an actual sign + if (Material.matchMaterial(arguments[1] + "_SIGN") == null) { + Stargate.getMessageSender().sendErrorMessage(commandSender, "The given sign type is invalid"); + return null; + } + String colorString = arguments[1] + ":"; + + //Validate the colors given by the user + String[] errorMessage = new String[]{"The given main sign color is invalid!", "The given highlight sign color is invalid!"}; + String[] newColors = new String[2]; + for (int i = 0; i < 2; i++) { + if (validatePerSignColor(arguments[i + 2])) { + newColors[i] = arguments[i + 2]; + } else { + Stargate.getMessageSender().sendErrorMessage(commandSender, errorMessage[i]); + return null; + } + } + colorString += String.join(",", newColors); + return colorString; + } + + /** + * Updates the per-sign colors with the given input + * + * @param signType

The sign type that is updated

+ * @param colorString

The new color string to replace any previous value with

+ * @param configuration

The file configuration to update with the new per-sign colors

+ */ + private void updatePerSignColors(String signType, String colorString, FileConfiguration configuration) { + List newColorStrings = new ArrayList<>(); + List oldColors = (List) Stargate.getStargateConfig().getConfigOptionsReference().get(ConfigOption.PER_SIGN_COLORS); + for (Object object : oldColors) { + newColorStrings.add(String.valueOf(object)); + } + newColorStrings.removeIf((item) -> item.startsWith(signType)); + newColorStrings.add(colorString); + + Stargate.getStargateConfig().getConfigOptionsReference().put(ConfigOption.PER_SIGN_COLORS, newColorStrings); + configuration.set(ConfigOption.PER_SIGN_COLORS.getConfigNode(), newColorStrings); + } + + /** + * Tries to validate one of the colors given when changing per-sign colors + * + * @param color

The color chosen by the user

+ * @return

True if the given color is valid

+ */ + private boolean validatePerSignColor(String color) { + ChatColor newHighlightColor = parseColor(color); + return newHighlightColor != null || color.equalsIgnoreCase("default") || + color.equalsIgnoreCase("inverted"); + } + + /** + * Saves the configuration file and reloads as necessary + * + * @param selectedOption

The config option that was changed

+ * @param commandSender

The command sender that executed the config command

+ */ + private void saveAndReload(ConfigOption selectedOption, CommandSender commandSender) { //Save the config file and reload if necessary Stargate.getInstance().saveConfig(); diff --git a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java index a324d39..c37de81 100644 --- a/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java +++ b/src/main/java/net/knarcraft/stargate/command/ConfigTabCompleter.java @@ -3,6 +3,8 @@ package net.knarcraft.stargate.command; import net.knarcraft.stargate.config.ConfigOption; import net.knarcraft.stargate.config.OptionDataType; import net.md_5.bungee.api.ChatColor; +import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; @@ -17,15 +19,26 @@ import java.util.List; */ public class ConfigTabCompleter implements TabCompleter { + private List signTypes; + private List booleans; + private List numbers; + private List chatColors; + private List languages; + private List extendedColors; + @Nullable @Override public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - + if (signTypes == null || booleans == null || numbers == null || chatColors == null || languages == null) { + initializeAutoCompleteLists(); + } if (args.length > 1) { ConfigOption selectedOption = ConfigOption.getByName(args[0]); if (selectedOption == null) { return new ArrayList<>(); + } else if (selectedOption.getDataType() == OptionDataType.STRING_LIST) { + return getPossibleStringListOptionValues(selectedOption, args); } else { return getPossibleOptionValues(selectedOption, args[1]); } @@ -63,18 +76,10 @@ public class ConfigTabCompleter implements TabCompleter { * @return

Some or all of the valid values for the option

*/ private List getPossibleOptionValues(ConfigOption selectedOption, String typedText) { - List booleans = new ArrayList<>(); - booleans.add("true"); - booleans.add("false"); - - List numbers = new ArrayList<>(); - numbers.add("0"); - numbers.add("5"); - switch (selectedOption) { case LANGUAGE: //Return available languages - return filterMatching(getLanguages(), typedText); + return filterMatching(languages, typedText); case GATE_FOLDER: case PORTAL_FOLDER: case DEFAULT_GATE_NETWORK: @@ -88,7 +93,7 @@ public class ConfigTabCompleter implements TabCompleter { case HIGHLIGHT_SIGN_COLOR: case FREE_GATES_COLOR: //Return all colors - return filterMatching(getColors(), typedText); + return filterMatching(chatColors, typedText); } //If the config value is a boolean, show the two boolean values @@ -104,50 +109,95 @@ public class ConfigTabCompleter implements TabCompleter { return new ArrayList<>(); } } - - //TODO: What to do with per-sign colors? - return null; } /** - * Gets all available languages + * Get possible values for the selected string list option * - * @return

The available languages

+ * @param selectedOption

The selected option

+ * @param args

The arguments given by the user

+ * @return

Some or all of the valid values for the option

*/ - private List getLanguages() { - List languages = new ArrayList<>(); - languages.add("de"); - languages.add("en"); - languages.add("es"); - languages.add("fr"); - languages.add("hu"); - languages.add("it"); - languages.add("nb-no"); - languages.add("nl"); - languages.add("nn-no"); - languages.add("pt-br"); - languages.add("ru"); - return languages; - } - - /** - * Gets all available colors - * - * @return

All available colors

- */ - private List getColors() { - List colors = new ArrayList<>(); - for (ChatColor color : getChatColors()) { - colors.add(color.getName()); + private List getPossibleStringListOptionValues(ConfigOption selectedOption, String[] args) { + if (selectedOption == ConfigOption.PER_SIGN_COLORS) { + return getPerSignColorCompletion(args); + } else { + return null; } - return colors; } /** - * Gets a list of all available chat colors + * Gets the tab completion values for completing the per-sign color text * - * @return

A list of chat colors

+ * @param args

The arguments given by the user

+ * @return

The options to give the user

+ */ + private List getPerSignColorCompletion(String[] args) { + if (args.length < 3) { + return filterMatching(signTypes, args[1]); + } else if (args.length < 4) { + return filterMatching(extendedColors, args[2]); + } else if (args.length < 5) { + return filterMatching(extendedColors, args[3]); + } + return new ArrayList<>(); + } + + /** + * Puts a single string value into a string list + * + * @param value

The string to make into a list

+ * @return

A list containing the string value

+ */ + private List putStringInList(String value) { + List list = new ArrayList<>(); + list.add(value); + return list; + } + + /** + * Initializes all lists of auto-completable values + */ + private void initializeAutoCompleteLists() { + booleans = new ArrayList<>(); + booleans.add("true"); + booleans.add("false"); + + numbers = new ArrayList<>(); + numbers.add("0"); + numbers.add("5"); + + signTypes = new ArrayList<>(); + for (Material material : Material.values()) { + if (Tag.STANDING_SIGNS.isTagged(material)) { + signTypes.add(material.toString().replace("_SIGN", "")); + } + } + + getColors(); + initializeLanguages(); + + extendedColors = new ArrayList<>(chatColors); + extendedColors.add("default"); + extendedColors.add("inverted"); + } + + + /** + * Initializes the list of chat colors + */ + private void getColors() { + chatColors = new ArrayList<>(); + for (ChatColor color : getChatColors()) { + chatColors.add(color.getName()); + } + } + + /** + * Gets available chat colors + * + * @return

The available chat colors

*/ private List getChatColors() { List chatColors = new ArrayList<>(); @@ -167,19 +217,29 @@ public class ConfigTabCompleter implements TabCompleter { chatColors.add(ChatColor.DARK_GRAY); chatColors.add(ChatColor.GRAY); chatColors.add(ChatColor.YELLOW); + chatColors.add(ChatColor.of("#ed76d9")); + chatColors.add(ChatColor.of("#ffecb7")); return chatColors; } /** - * Puts a single string value into a string list - * - * @param value

The string to make into a list

- * @return

A list containing the string value

+ * Initializes the list of all available languages */ - private List putStringInList(String value) { - List list = new ArrayList<>(); - list.add(value); - return list; + private void initializeLanguages() { + languages = new ArrayList<>(); + languages.add("de"); + languages.add("en"); + languages.add("es"); + languages.add("fr"); + languages.add("hu"); + languages.add("it"); + languages.add("nb-no"); + languages.add("nl"); + languages.add("nn-no"); + languages.add("pt-br"); + languages.add("ru"); + //TODO: Generate this list dynamically by listing the language files in the jar and adding the user's custom + // language files } } diff --git a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java index 95dea52..49c9083 100644 --- a/src/main/java/net/knarcraft/stargate/config/ConfigTag.java +++ b/src/main/java/net/knarcraft/stargate/config/ConfigTag.java @@ -7,7 +7,8 @@ import java.util.Arrays; */ public enum ConfigTag { - COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, ConfigOption.HIGHLIGHT_SIGN_COLOR}), + COLOR(new ConfigOption[]{ConfigOption.FREE_GATES_COLOR, ConfigOption.MAIN_SIGN_COLOR, + ConfigOption.HIGHLIGHT_SIGN_COLOR, ConfigOption.PER_SIGN_COLORS}), FOLDER(new ConfigOption[]{ConfigOption.GATE_FOLDER, ConfigOption.PORTAL_FOLDER}); private final ConfigOption[] taggedOptions; @@ -38,7 +39,7 @@ public enum ConfigTag { * @return

True if changing the config option requires a "reload of colors" to take effect

*/ public static boolean requiresColorReload(ConfigOption configOption) { - return COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR; + return (COLOR.isTagged(configOption) && configOption != ConfigOption.FREE_GATES_COLOR); } /**