package net.knarcraft.stargatecommand.command; import net.TheDgtl.Stargate.config.ConfigurationAPI; import net.TheDgtl.Stargate.config.ConfigurationOption; import net.TheDgtl.Stargate.config.OptionDataType; import net.knarcraft.stargatecommand.formatting.StringFormat; import net.knarcraft.stargatecommand.formatting.StringFormatter; import net.knarcraft.stargatecommand.formatting.TranslatableMessage; import net.knarcraft.stargatecommand.property.StargateCommandCommand; import net.md_5.bungee.api.ChatColor; import org.apache.commons.lang.StringUtils; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.List; import static net.knarcraft.stargatecommand.formatting.StringFormatter.getTranslatedErrorMessage; import static net.knarcraft.stargatecommand.formatting.StringFormatter.getTranslatedInfoMessage; /** * This command represents the config command for changing config values */ public class CommandConfig implements CommandExecutor { private final ConfigurationAPI configurationAPI; private final List bannedConfigOptions; /** * Instantiates a new instance of the config command * * @param configurationAPI

A reference to the Stargate API

* @param bannedConfigOptions

A list of config options that shouldn't be available

*/ public CommandConfig(ConfigurationAPI configurationAPI, List bannedConfigOptions) { super(); this.configurationAPI = configurationAPI; this.bannedConfigOptions = bannedConfigOptions; } @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { if (commandSender instanceof Player player) { if (!player.hasPermission(StargateCommandCommand.CONFIG.getPermissionNode())) { player.sendMessage(getTranslatedErrorMessage(TranslatableMessage.PERMISSION_DENIED)); return true; } } if (args.length > 0) { ConfigurationOption selectedOption; try { selectedOption = ConfigurationOption.valueOf(args[0].toUpperCase()); if (bannedConfigOptions.contains(selectedOption)) { return true; } } catch (IllegalArgumentException exception) { commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_CONFIGURATION_OPTION)); return true; } if (args.length > 1) { updateConfigValue(selectedOption, commandSender, args[1]); } else { //Display info and the current value of the given config value printConfigOptionValue(commandSender, selectedOption); } return true; } else { //Display all config options displayConfigValues(commandSender); } return true; } /** * Updates a 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 updateConfigValue(ConfigurationOption selectedOption, CommandSender commandSender, String value) { //Validate any sign colors if (selectedOption.getDataType() == OptionDataType.COLOR) { try { ChatColor.of(value.toUpperCase()); } catch (IllegalArgumentException | NullPointerException ignored) { commandSender.sendMessage(StringFormatter.replacePlaceholder(getTranslatedErrorMessage( TranslatableMessage.INVALID_DATATYPE_GIVEN), "{datatype}", "color")); return; } } OptionDataType optionDataType = selectedOption.getDataType(); Object typeCastedValue; //Validate the input based on the data type switch (optionDataType) { case INTEGER -> { Integer intValue = getInteger(commandSender, selectedOption, value); if (intValue == null) { return; } else { typeCastedValue = intValue; } } case DOUBLE -> { Double doubleValue = getDouble(commandSender, selectedOption, value); if (doubleValue == null) { return; } else { typeCastedValue = doubleValue; } } case BOOLEAN -> typeCastedValue = Boolean.parseBoolean(value); default -> typeCastedValue = value; } /* Test any option data type with a defined set of values. * Color is excluded as it has a near-infinite number of valid values. */ if (optionDataType != OptionDataType.COLOR && optionDataType.getValues() != null && optionDataType.getValues().length > 0) { if (!checkIfValueMatchesDatatype(optionDataType, value, commandSender)) { return; } } configurationAPI.setConfigurationOptionValue(selectedOption, typeCastedValue); saveAndReload(commandSender); } /** * Checks if the given value is valid for the given option data type and warns if it isn't * * @param dataType

The expected type for the value

* @param value

The value to check

* @param commandSender

The command sender to warn about invalid values

* @return

True if the given value is valid for the option data type

*/ private boolean checkIfValueMatchesDatatype(OptionDataType dataType, String value, CommandSender commandSender) { if (!matchesOptionDataType(dataType, value)) { commandSender.sendMessage(StringFormatter.replacePlaceholder(getTranslatedErrorMessage( TranslatableMessage.INVALID_DATATYPE_GIVEN), "{datatype}", dataType.name().toLowerCase().replace('_', ' '))); return false; } else { return true; } } /** * Checks if the given value is valid for the given option data type * * @param dataType

The expected type for the value

* @param value

The value to check

* @return

True if the given value is valid for the option data type

*/ private boolean matchesOptionDataType(OptionDataType dataType, String value) { return Arrays.asList(dataType.getValues()).contains(value); } /** * Saves the configuration file and reloads * * @param commandSender

The command sender that executed the config command

*/ private void saveAndReload(CommandSender commandSender) { configurationAPI.saveConfiguration(); configurationAPI.reload(); commandSender.sendMessage(getTranslatedInfoMessage(TranslatableMessage.CONFIG_UPDATED)); } /** * Gets an integer from a string * * @param commandSender

The command sender that sent the config command

* @param selectedOption

The option the command sender is trying to change

* @param value

The value given

* @return

An integer, or null if it was invalid

*/ private Integer getInteger(CommandSender commandSender, ConfigurationOption selectedOption, String value) { try { int intValue = Integer.parseInt(value); if ((selectedOption == ConfigurationOption.USE_COST || selectedOption == ConfigurationOption.CREATION_COST) && intValue < 0) { commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.POSITIVE_NUMBER_REQUIRED)); return null; } return intValue; } catch (NumberFormatException exception) { commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_NUMBER_GIVEN)); return null; } } /** * Gets a double from a string * * @param commandSender

The command sender that sent the config command

* @param selectedOption

The option the command sender is trying to change

* @param value

The value given

* @return

A double, or null if it was invalid

*/ private Double getDouble(CommandSender commandSender, ConfigurationOption selectedOption, String value) { try { double doubleValue = Double.parseDouble(value); if (selectedOption == ConfigurationOption.GATE_EXIT_SPEED_MULTIPLIER && doubleValue < 0) { commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.POSITIVE_NUMBER_REQUIRED)); return null; } return doubleValue; } catch (NumberFormatException exception) { commandSender.sendMessage(getTranslatedErrorMessage(TranslatableMessage.INVALID_NUMBER_GIVEN)); return null; } } /** * Prints information about a config option and its current value * * @param sender

The command sender that sent the command

* @param option

The config option to print information about

*/ private void printConfigOptionValue(CommandSender sender, ConfigurationOption option) { Object value = configurationAPI.getConfigurationOptionValue(option); String description = getOptionDescription(option); String currentValue = StringFormatter.replacePlaceholder(StringFormatter.getStringFormat( StringFormat.CONFIG_OPTION_CURRENT_VALUE_FORMAT), "{value}", String.valueOf(value)); sender.sendMessage(StringFormatter.formatInfoMessage(description + currentValue)); } /** * Displays the name and a small description of every config value * * @param sender

The command sender to display the config list to

*/ private void displayConfigValues(CommandSender sender) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(StringFormatter.getStringFormat(StringFormat.CONFIG_VALUES_HEADER_FORMAT)); for (ConfigurationOption option : ConfigurationOption.values()) { if (!bannedConfigOptions.contains(option)) { stringBuilder.append(getOptionDescription(option)); } } sender.sendMessage(stringBuilder.toString()); } /** * Gets the description of a single config option * * @param option

The option to describe

* @return

A string describing the config option

*/ private String getOptionDescription(ConfigurationOption option) { Object defaultValue = option.getDefaultValue(); String stringValue = String.valueOf(defaultValue); if (option.getDataType() == OptionDataType.STRING_LIST) { stringValue = "[" + StringUtils.join((String[]) defaultValue, ",") + "]"; } return StringFormatter.replacePlaceholders(StringFormatter.getStringFormat( StringFormat.CONFIG_OPTION_DESCRIPTION_FORMAT), new String[]{"{name}", "{description}", "{value}"}, new String[]{option.name(), option.getDescription(), stringValue}); } }