diff --git a/pom.xml b/pom.xml
index 0c68d4d..2bd1de6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
net.azalealibrary
configuration
- 1.1.2
+ 2.0.0
@@ -44,12 +44,6 @@
spigot-api
${mcVersion}-R0.1-SNAPSHOT
-
-
- org.spigotmc
- plugin-annotations
- 1.2.3-SNAPSHOT
-
com.github.seeseemelk
diff --git a/src/main/java/net/azalealibrary/configuration/AzaleaConfiguration.java b/src/main/java/net/azalealibrary/configuration/AzaleaConfiguration.java
deleted file mode 100644
index e194cb8..0000000
--- a/src/main/java/net/azalealibrary/configuration/AzaleaConfiguration.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.command.AzaleaCommandApi;
-import org.bukkit.plugin.PluginDescriptionFile;
-import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.plugin.java.JavaPluginLoader;
-import org.bukkit.plugin.java.annotation.dependency.Dependency;
-import org.bukkit.plugin.java.annotation.plugin.ApiVersion;
-import org.bukkit.plugin.java.annotation.plugin.Plugin;
-
-import java.io.File;
-
-@SuppressWarnings("unused")
-@Plugin(name = "AzaleaConfiguration", version = "1.0")
-@Dependency("AzaleaCommand")
-@ApiVersion(ApiVersion.Target.v1_19)
-public final class AzaleaConfiguration extends JavaPlugin {
-
- public AzaleaConfiguration() { }
-
- public AzaleaConfiguration(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
- super(loader, description, dataFolder, file);
- }
-
- @Override
- public void onLoad() {
- AzaleaCommandApi.register(this, new ConfigureCommand());
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/AzaleaConfigurationApi.java b/src/main/java/net/azalealibrary/configuration/AzaleaConfigurationApi.java
deleted file mode 100644
index fa722da..0000000
--- a/src/main/java/net/azalealibrary/configuration/AzaleaConfigurationApi.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.command.AzaleaException;
-import org.bukkit.plugin.Plugin;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public final class AzaleaConfigurationApi {
-
- private static final List CONFIGURATIONS = new ArrayList<>();
-
- public static List getConfigurations() {
- return CONFIGURATIONS;
- }
-
- public static @Nullable Configuration getConfiguration(String name) {
- return CONFIGURATIONS.stream().filter(c -> c.getName().equals(name)).findFirst().orElse(null);
- }
-
- public static C register(C configurable) {
- Configuration configuration = getConfiguration(configurable.getName());
-
- if (configuration != null) {
- configuration.merge(configurable);
- } else {
- Configuration newConfiguration = new Configuration(configurable.getName());
- newConfiguration.merge(configurable);
- CONFIGURATIONS.add(newConfiguration);
- }
- return configurable;
- }
-
- public static C unregister(C configurable) {
- Configuration configuration = getConfiguration(configurable.getName());
-
- if (configuration != null) {
- configuration.unmerge(configurable);
- }
- return configurable;
- }
-
- public static void load(Plugin plugin, Configurable configurable) {
- getFileConfiguration(plugin, configurable.getName()).load(configurable);
- register(configurable);
- }
-
- public static void unload(Plugin plugin, Configurable configurable) {
- save(plugin, configurable);
- unregister(configurable);
- }
-
- public static void save(Plugin plugin, Configurable configurable) {
- getFileConfiguration(plugin, configurable.getName()).save(configurable);
- }
-
- public static FileConfiguration getFileConfiguration(Plugin plugin, String name) {
- return getFileConfiguration(plugin, "/", name);
- }
-
- public static FileConfiguration getFileConfiguration(Plugin plugin, String path, String name) {
- File directory = new File(plugin.getDataFolder(), path);
-
- if (!directory.exists() & !directory.mkdir() || !directory.isDirectory()) {
- throw new AzaleaException(directory.getName() + " is not a directory.");
- }
-
- File file = new File(directory, name + ".yml");
-
- try {
- if (!file.exists() & !file.createNewFile()) {
- throw new AzaleaException(directory.getName() + " is not a directory.");
- }
- } catch (Exception exception) {
- throw new AzaleaException("Could not create configuration file '" + name + "'.", exception);
- }
- return new FileConfiguration(plugin, file);
- }
-
- public static List getAllFileConfigurations(Plugin plugin) {
- return getAllFileConfigurations(plugin, "/");
- }
-
- public static List getAllFileConfigurations(Plugin plugin, String path) {
- File directory = new File(plugin.getDataFolder(), path);
-
- if (!directory.exists() & !directory.mkdir() || !directory.isDirectory()) {
- throw new AzaleaException(directory.getName() + " is not a directory.");
- }
-
- File[] files = directory.listFiles(file -> {
- String name = file.getName();
- int dotIndex = name.lastIndexOf('.');
- String extension = dotIndex > 0 ? name.substring(dotIndex + 1) : "";
- return extension.equals("yaml") || extension.equals("yml");
- });
- return files != null ? Arrays.stream(files).map(f -> new FileConfiguration(plugin, f)).toList() : List.of();
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/Configurable.java b/src/main/java/net/azalealibrary/configuration/Configurable.java
deleted file mode 100644
index 94cb8c8..0000000
--- a/src/main/java/net/azalealibrary/configuration/Configurable.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.configuration.property.ConfigurableProperty;
-
-import java.util.List;
-import java.util.Optional;
-
-public interface Configurable {
-
- String getName();
-
- List> getProperties();
-
- default Optional> getProperty(ConfigurableProperty, ?> property) {
- return getProperties().stream().filter(p -> p.equals(property)).findFirst();
- }
-
- @SuppressWarnings("unchecked")
- default T getValue(ConfigurableProperty property) {
- return (T) getProperty(property).orElseThrow(() -> new RuntimeException("Could not find property '" + property.getName() + "'.")).get();
- }
-
- @SuppressWarnings("unchecked")
- default void setValue(ConfigurableProperty property, T value) {
- ((ConfigurableProperty) getProperty(property).orElseThrow(() -> new RuntimeException("Could not find property '" + property.getName() + "'."))).set((P) value);
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/Configuration.java b/src/main/java/net/azalealibrary/configuration/Configuration.java
deleted file mode 100644
index 28157a9..0000000
--- a/src/main/java/net/azalealibrary/configuration/Configuration.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.command.AzaleaException;
-import net.azalealibrary.configuration.property.ConfigurableProperty;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Configuration implements Configurable {
-
- private final String name;
- private final List> properties;
-
- public Configuration(String name) {
- this.name = name;
- this.properties = new ArrayList<>();
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public List> getProperties() {
- return properties;
- }
-
- public void merge(Configurable configurable) {
- if (!configurable.getName().equals(name)) {
- throw new AzaleaException(String.format("Attempting to merge incompatible configurations '%s' into '%s'.", configurable.getName(), name));
- }
-
- for (ConfigurableProperty, ?> property : configurable.getProperties()) {
- if (properties.contains(property)) {
- throw new AzaleaException(String.format("Attempting to merge configuration with existing property: %s", property.getName()));
- }
- properties.add(property);
- }
- }
-
- public void unmerge(Configurable configurable) {
- if (!configurable.getName().equals(name)) {
- throw new AzaleaException(String.format("Attempting to unmerge incompatible configurations '%s' into '%s'.", configurable.getName(), name));
- }
- properties.removeAll(configurable.getProperties());
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/ConfigureCommand.java b/src/main/java/net/azalealibrary/configuration/ConfigureCommand.java
deleted file mode 100644
index c253b35..0000000
--- a/src/main/java/net/azalealibrary/configuration/ConfigureCommand.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.command.Arguments;
-import net.azalealibrary.command.AzaleaException;
-import net.azalealibrary.command.CommandNode;
-import net.azalealibrary.command.TextUtil;
-import net.azalealibrary.configuration.property.ConfigurableProperty;
-import net.azalealibrary.configuration.property.ListProperty;
-import org.bukkit.ChatColor;
-import org.bukkit.command.CommandSender;
-
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class ConfigureCommand extends CommandNode {
-
- private static final String INDENT = " ";
-
- public ConfigureCommand() {
- super("configure");
- }
-
- @Override
- public @Nullable String getPermission() {
- return "azalea.configure";
- }
-
- @Override
- public List complete(CommandSender sender, Arguments arguments) {
- if (arguments.size() == 1) {
- return AzaleaConfigurationApi.getConfigurations().stream().map(Configurable::getName).toList();
- } else if (arguments.size() == 2) {
- return Arrays.stream(Action.values()).map(v -> v.name().toLowerCase()).toList();
- } else {
- Configurable configuration = arguments.find(0, "configuration", AzaleaConfigurationApi::getConfiguration);
- Action action = arguments.find(1, "action", input -> Action.valueOf(input.toUpperCase()));
- List> properties = configuration.getProperties();
-
- if (arguments.size() == 3) {
- return properties.stream().filter(ConfigurableProperty::isEditable).map(ConfigurableProperty::getName).toList();
- } else if (arguments.size() > 3 && action == Action.SET) {
- return properties.stream()
- .filter(ConfigurableProperty::isEditable)
- .filter(p -> p.getName().equals(arguments.get(2)))
- .findFirst().map(p -> p.onComplete(sender, arguments.subArguments(3)))
- .orElse(List.of());
- }
- }
- return new ArrayList<>();
- }
-
- @Override
- public void execute(CommandSender sender, Arguments arguments) {
- Configurable configuration = arguments.find(0, "configuration", AzaleaConfigurationApi::getConfiguration);
- Action action = arguments.find(1, "action", input -> Action.valueOf(input.toUpperCase()));
- Arguments sub = arguments.subArguments(3);
- List> properties = arguments.find(2, "property", input -> configuration.getProperties().stream()
- .filter(ConfigurableProperty::isEditable)
- .filter(c -> action.predicate.test(sender, sub, input, c))
- .toList());
-
- if (properties.isEmpty()) {
- throw new AzaleaException("No properties found.");
- }
-
- switch (action) {
- case SET -> {
- properties.forEach(p -> p.onExecute(sender, sub));
- sender.sendMessage(getMessage(properties, "updated"));
- }
- case RESET -> {
- properties.forEach(ConfigurableProperty::reset);
- sender.sendMessage(getMessage(properties, "reset"));
- }
- case INFO -> {
- ConfigurableProperty, ?> property = properties.get(0);
-
- List info = new ArrayList<>();
- info.add(ChatColor.LIGHT_PURPLE + property.getName() + ChatColor.RESET + "=" + ChatColor.YELLOW + property);
- property.getDescription().forEach(l -> info.addAll(TextUtil.split(l, 55).stream().map(i -> ChatColor.GRAY + INDENT + i).toList()));
- sender.sendMessage(info.toArray(String[]::new));
- }
- }
- }
-
- private static String[] getMessage(List> properties, String action) {
- List lines = new ArrayList<>();
- lines.add(String.valueOf(ChatColor.YELLOW) + properties.size() + ChatColor.RESET +
- (properties.size() > 1 ? " properties" : " property") +
- (properties.size() > 1 ? " have" : " has") + " been " + action + ":");
- lines.addAll(properties.stream().map(p -> INDENT + ChatColor.LIGHT_PURPLE + p.getName()).toList());
- return lines.toArray(String[]::new);
- }
-
- private enum Action {
- SET((s, a, i, c) -> c instanceof ListProperty> ? c.getName().equals(i) : c.getName().matches(i) && c.getPropertyType().test(s, a)),
- RESET((s, a, i, c) -> c.getName().matches(i)),
- INFO((s, a, i, c) -> c.getName().equals(i));
-
- final ActionTester predicate;
-
- Action(ActionTester predicate) {
- this.predicate = predicate;
- }
-
- @FunctionalInterface
- private interface ActionTester {
- boolean test(CommandSender sender, Arguments arguments, String input, ConfigurableProperty, ?> property);
- }
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/FileConfiguration.java b/src/main/java/net/azalealibrary/configuration/FileConfiguration.java
deleted file mode 100644
index 6433e3a..0000000
--- a/src/main/java/net/azalealibrary/configuration/FileConfiguration.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package net.azalealibrary.configuration;
-
-import net.azalealibrary.command.TextUtil;
-import net.azalealibrary.configuration.property.ConfigurableProperty;
-import net.azalealibrary.configuration.property.ListProperty;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.plugin.Plugin;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-
-public class FileConfiguration {
-
- private final Plugin plugin;
- private final File file;
- private final YamlConfiguration configuration;
-
- public FileConfiguration(Plugin plugin, File file) {
- this.plugin = plugin;
- this.file = file;
- this.configuration = YamlConfiguration.loadConfiguration(file);
- }
-
- public String getName() {
- return file.getName().substring(0, file.getName().indexOf('.'));
- }
-
- public File getFile() {
- return file;
- }
-
- public YamlConfiguration getYamlConfiguration() {
- return configuration;
- }
-
- public void load(Configurable configurable) {
- try {
- plugin.getLogger().log(Level.INFO, "Loading '" + configurable.getName() + "' data.");
-
- for (ConfigurableProperty, ?> property : configurable.getProperties()) {
- property.deserialize(configuration);
- }
- } catch (Exception exception) {
- plugin.getLogger().log(Level.WARNING, exception, () -> "Could not load '" + configurable.getName() + "' data.");
- }
- }
-
- public void save(Configurable configurable) {
- try {
- plugin.getLogger().log(Level.INFO, "Saving '" + configurable.getName() + "' data.");
-
- for (ConfigurableProperty, ?> property : configurable.getProperties()) {
- property.serialize(configuration);
- List comments = new ArrayList<>();
- String type = property.getPropertyType().getExpected() + (property instanceof ListProperty> ? " (list)" : "");
- comments.add("Property: " + property.getName() + " of " + type);
- comments.add("Default: " + property.getDefault());
- property.getDescription().forEach(l -> comments.addAll(TextUtil.split(l, 55).stream().map(i -> " " + i).toList()));
- configuration.setComments(property.getName(), comments);
- }
- configuration.save(file);
- } catch (Exception exception) {
- plugin.getLogger().log(Level.WARNING, exception, () -> "Could not save '" + configurable.getName() + "'.");
- }
- }
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof FileConfiguration fileConfiguration) {
- return plugin.equals(fileConfiguration.plugin) && file.equals(fileConfiguration.file);
- }
- return super.equals(object);
- }
-
- @Override
- public String toString() {
- return String.format("path:%s, plugin:%s", file.getPath(), plugin.getName());
- }
-}
diff --git a/src/main/java/net/azalealibrary/configuration/command/ConfigureCommand.java b/src/main/java/net/azalealibrary/configuration/command/ConfigureCommand.java
new file mode 100644
index 0000000..ef0eda8
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/ConfigureCommand.java
@@ -0,0 +1,24 @@
+package net.azalealibrary.configuration.command;
+
+import net.azalealibrary.command.CommandNode;
+import net.azalealibrary.configuration.command.property.InfoSubcommand;
+import net.azalealibrary.configuration.command.property.ResetSubcommand;
+import net.azalealibrary.configuration.command.property.SetSubcommand;
+import net.azalealibrary.configuration.config.Configuration;
+
+public class ConfigureCommand extends CommandNode {
+
+ public ConfigureCommand(Configuration configuration) {
+ this(configuration.getName(), configuration);
+ }
+
+ public ConfigureCommand(String name, Configuration configuration) {
+ super(name,
+ new ReloadSubcommand(configuration),
+ new SaveSubcommand(configuration),
+ new InfoSubcommand(configuration),
+ new ResetSubcommand(configuration),
+ new SetSubcommand(configuration)
+ );
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/ReloadSubcommand.java b/src/main/java/net/azalealibrary/configuration/command/ReloadSubcommand.java
new file mode 100644
index 0000000..ad6b60c
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/ReloadSubcommand.java
@@ -0,0 +1,23 @@
+package net.azalealibrary.configuration.command;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.command.CommandNode;
+import net.azalealibrary.configuration.config.Configuration;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+
+public class ReloadSubcommand extends CommandNode {
+
+ private final Configuration configuration;
+
+ public ReloadSubcommand(Configuration configuration) {
+ super("reload");
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void execute(CommandSender sender, Arguments arguments) {
+ configuration.load();
+ sender.sendMessage(ChatColor.LIGHT_PURPLE + "Reloaded '" + configuration.getName() + "' to file system.");
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/SaveSubcommand.java b/src/main/java/net/azalealibrary/configuration/command/SaveSubcommand.java
new file mode 100644
index 0000000..cf486b0
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/SaveSubcommand.java
@@ -0,0 +1,23 @@
+package net.azalealibrary.configuration.command;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.command.CommandNode;
+import net.azalealibrary.configuration.config.Configuration;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+
+public class SaveSubcommand extends CommandNode {
+
+ private final Configuration configuration;
+
+ public SaveSubcommand(Configuration configuration) {
+ super("save");
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void execute(CommandSender sender, Arguments arguments) {
+ configuration.save();
+ sender.sendMessage(ChatColor.LIGHT_PURPLE + "Saved '" + configuration.getName() + "' to file system.");
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/property/InfoSubcommand.java b/src/main/java/net/azalealibrary/configuration/command/property/InfoSubcommand.java
new file mode 100644
index 0000000..4061308
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/property/InfoSubcommand.java
@@ -0,0 +1,31 @@
+package net.azalealibrary.configuration.command.property;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.command.TextUtil;
+import net.azalealibrary.configuration.config.Configuration;
+import net.azalealibrary.configuration.property.ConfigurableProperty;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InfoSubcommand extends PropertySubcommand {
+
+ public InfoSubcommand(Configuration configuration) {
+ super("info", configuration);
+ }
+
+ @Override
+ protected boolean isSelected(Arguments arguments, ConfigurableProperty, ?> property) {
+ return arguments.isEmpty() || property.getName().matches(arguments.get(0).replace("*", ".*")) && arguments.size() == 1;
+ }
+
+ @Override
+ protected void execute(CommandSender sender, Arguments arguments, ConfigurableProperty, ?> property) {
+ List info = new ArrayList<>();
+ info.add(ChatColor.LIGHT_PURPLE + property.getName() + ChatColor.RESET + "=" + ChatColor.YELLOW + property);
+ property.getDescription().stream().flatMap(l -> TextUtil.split(l, 55).stream().map(i -> ChatColor.GRAY + " " + i)).forEach(info::add);
+ sender.sendMessage(info.toArray(String[]::new));
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/property/PropertySubcommand.java b/src/main/java/net/azalealibrary/configuration/command/property/PropertySubcommand.java
new file mode 100644
index 0000000..84ff4ba
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/property/PropertySubcommand.java
@@ -0,0 +1,51 @@
+package net.azalealibrary.configuration.command.property;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.command.AzaleaException;
+import net.azalealibrary.command.CommandNode;
+import net.azalealibrary.configuration.config.Configuration;
+import net.azalealibrary.configuration.property.ConfigurableProperty;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+
+public abstract class PropertySubcommand extends CommandNode {
+
+ private final List> properties;
+
+ public PropertySubcommand(String name, Configuration configuration) {
+ super(name);
+
+ properties = configuration.getProperties().stream()
+ .filter(ConfigurableProperty::isEditable)
+ .toList();
+ }
+
+ protected abstract boolean isSelected(Arguments arguments, ConfigurableProperty, ?> property);
+
+ @Override
+ public List complete(CommandSender sender, Arguments arguments) {
+ if (arguments.size() == 1) {
+ return properties.stream().map(ConfigurableProperty::getName).toList();
+ }
+ List> selected = properties.stream()
+ .filter(p -> isSelected(arguments, p))
+ .toList();
+
+ if (selected.isEmpty()) {
+ throw new AzaleaException("No properties found.");
+ }
+ return selected.stream().findFirst()
+ .map(p -> p.onComplete(sender, arguments.subArguments(1)))
+ .orElse(List.of());
+ }
+
+ @Override
+ public void execute(CommandSender sender, Arguments arguments) {
+ for (ConfigurableProperty, ?> property : properties.stream().filter(p -> isSelected(arguments, p)).toList()) {
+ execute(sender, arguments, property);
+ }
+ }
+
+ protected abstract void execute(CommandSender sender, Arguments arguments, ConfigurableProperty, ?> property);
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/property/ResetSubcommand.java b/src/main/java/net/azalealibrary/configuration/command/property/ResetSubcommand.java
new file mode 100644
index 0000000..872cb3d
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/property/ResetSubcommand.java
@@ -0,0 +1,27 @@
+package net.azalealibrary.configuration.command.property;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.configuration.config.Configuration;
+import net.azalealibrary.configuration.property.ConfigurableProperty;
+import net.md_5.bungee.api.ChatColor;
+import org.bukkit.command.CommandSender;
+
+public class ResetSubcommand extends PropertySubcommand {
+
+ public ResetSubcommand(Configuration configuration) {
+ super("reset", configuration);
+ }
+
+ @Override
+ protected boolean isSelected(Arguments arguments, ConfigurableProperty, ?> property) {
+ return arguments.isEmpty() || property.getName().matches(arguments.get(0).replace("*", ".*")) && arguments.size() == 1;
+ }
+
+ @Override
+ protected void execute(CommandSender sender, Arguments arguments, ConfigurableProperty, ?> property) {
+ property.reset();
+ String name = ChatColor.LIGHT_PURPLE + property.getName() + ChatColor.RESET;
+ String value = ChatColor.YELLOW + property.get().toString();
+ sender.sendMessage("Property " + name + " has been reset to " + value + ".");
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/command/property/SetSubcommand.java b/src/main/java/net/azalealibrary/configuration/command/property/SetSubcommand.java
new file mode 100644
index 0000000..043084e
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/command/property/SetSubcommand.java
@@ -0,0 +1,27 @@
+package net.azalealibrary.configuration.command.property;
+
+import net.azalealibrary.command.Arguments;
+import net.azalealibrary.configuration.config.Configuration;
+import net.azalealibrary.configuration.property.ConfigurableProperty;
+import net.md_5.bungee.api.ChatColor;
+import org.bukkit.command.CommandSender;
+
+public class SetSubcommand extends PropertySubcommand {
+
+ public SetSubcommand(Configuration configuration) {
+ super("set", configuration);
+ }
+
+ @Override
+ protected boolean isSelected(Arguments arguments, ConfigurableProperty, ?> property) {
+ return property.getName().equals(arguments.get(0));
+ }
+
+ @Override
+ protected void execute(CommandSender sender, Arguments arguments, ConfigurableProperty, ?> property) {
+ property.onExecute(sender, arguments.subArguments(1));
+ String name = ChatColor.LIGHT_PURPLE + property.getName() + ChatColor.RESET;
+ String value = ChatColor.YELLOW + property.get().toString();
+ sender.sendMessage("Property " + name + " has updated to " + value + ".");
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/config/ConfigProperty.java b/src/main/java/net/azalealibrary/configuration/config/ConfigProperty.java
new file mode 100644
index 0000000..6260038
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/config/ConfigProperty.java
@@ -0,0 +1,7 @@
+package net.azalealibrary.configuration.config;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ConfigProperty { }
diff --git a/src/main/java/net/azalealibrary/configuration/config/Configuration.java b/src/main/java/net/azalealibrary/configuration/config/Configuration.java
new file mode 100644
index 0000000..dd4e69c
--- /dev/null
+++ b/src/main/java/net/azalealibrary/configuration/config/Configuration.java
@@ -0,0 +1,95 @@
+package net.azalealibrary.configuration.config;
+
+import net.azalealibrary.command.AzaleaException;
+import net.azalealibrary.command.TextUtil;
+import net.azalealibrary.configuration.property.ConfigurableProperty;
+import net.azalealibrary.configuration.property.ListProperty;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+public abstract class Configuration {
+
+ private final JavaPlugin plugin;
+ private final String name;
+ private final File file;
+ private final YamlConfiguration configuration;
+
+ public Configuration(JavaPlugin plugin, String name) {
+ this.plugin = plugin;
+ this.name = name;
+ this.file = getFile();
+ this.configuration = YamlConfiguration.loadConfiguration(file);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void load() {
+ try {
+ plugin.getLogger().log(Level.INFO, "Loading '" + getName() + "' data.");
+
+ for (ConfigurableProperty, ?> property : getProperties()) {
+ property.deserialize(configuration);
+ }
+ } catch (Exception exception) {
+ plugin.getLogger().log(Level.WARNING, exception, () -> "Could not load '" + getName() + "' data.");
+ }
+ }
+
+ public void save() {
+ try {
+ plugin.getLogger().log(Level.INFO, "Saving '" + getName() + "' data.");
+
+ for (ConfigurableProperty, ?> property : getProperties()) {
+ property.serialize(configuration);
+ List comments = new ArrayList<>();
+ String type = property.getPropertyType().getExpected() + (property instanceof ListProperty> ? " (list)" : "");
+ comments.add("Property: " + property.getName() + " of " + type);
+ comments.add("Default: " + property.getDefault());
+ property.getDescription().forEach(l -> comments.addAll(TextUtil.split(l, 55).stream().map(i -> " " + i).toList()));
+ configuration.setComments(property.getName(), comments);
+ }
+ configuration.save(file);
+ } catch (Exception exception) {
+ plugin.getLogger().log(Level.WARNING, exception, () -> "Could not save '" + getName() + "'.");
+ }
+ }
+
+ private File getFile() {
+ try {
+ File file = new File(plugin.getDataFolder(), getName() + ".yml");
+
+ if (!plugin.getDataFolder().exists() && plugin.getDataFolder().mkdir() && !file.exists()) {
+ file.createNewFile();
+ save(); // set initial config data
+ }
+ return file;
+ } catch (Exception exception) {
+ throw new AzaleaException("Could not create configuration file '" + file + "'.", exception);
+ }
+ }
+
+ public List> getProperties() {
+ List> properties = new ArrayList<>();
+
+ for (Field field : getClass().getDeclaredFields()) {
+ if (field.isAnnotationPresent(ConfigProperty.class)) {
+ try {
+ field.setAccessible(true);
+
+ if (field.get(this) instanceof ConfigurableProperty, ?> property) {
+ properties.add(property);
+ }
+ } catch (IllegalAccessException ignored) { }
+ }
+ }
+ return properties;
+ }
+}
diff --git a/src/main/java/net/azalealibrary/configuration/property/ConfigurableProperty.java b/src/main/java/net/azalealibrary/configuration/property/ConfigurableProperty.java
index bb01c9d..e157210 100644
--- a/src/main/java/net/azalealibrary/configuration/property/ConfigurableProperty.java
+++ b/src/main/java/net/azalealibrary/configuration/property/ConfigurableProperty.java
@@ -94,4 +94,12 @@ public List onComplete(CommandSender sender, Arguments arguments) {
public abstract void serialize(@Nonnull ConfigurationSection configuration);
public abstract void deserialize(@Nonnull ConfigurationSection configuration);
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Property> property) {
+ return property.name.equals(name) && property.propertyType.equals(propertyType);
+ }
+ return super.equals(object);
+ }
}
diff --git a/src/main/java/net/azalealibrary/configuration/property/ListProperty.java b/src/main/java/net/azalealibrary/configuration/property/ListProperty.java
index 01f5d16..399dc7a 100644
--- a/src/main/java/net/azalealibrary/configuration/property/ListProperty.java
+++ b/src/main/java/net/azalealibrary/configuration/property/ListProperty.java
@@ -77,20 +77,15 @@ public void deserialize(@Nonnull ConfigurationSection configuration) {
}
}
- @Override
- public boolean equals(Object object) {
- if (object instanceof ListProperty> property) {
- return property.name.equals(name) && property.propertyType.getType().equals(propertyType.getType());
- }
- return super.equals(object);
- }
-
@Override
public String toString() {
- return isSet() ? get().stream().map(propertyType::print).collect(Collectors.joining(", ")) : "";
+ return isSet() && !get().isEmpty() ? get().stream().map(propertyType::print).collect(Collectors.joining(", ")) : "";
}
public static Builder create(PropertyType type, String name, Supplier> defaultValue) {
+ if (!name.matches("[a-zA-Z0-9_]+")) {
+ throw new IllegalArgumentException("Property '" + name + "' contains non-alphanumeric characters.");
+ }
return new Builder<>(type, name, defaultValue);
}
diff --git a/src/main/java/net/azalealibrary/configuration/property/Property.java b/src/main/java/net/azalealibrary/configuration/property/Property.java
index 5787bd4..8f326e6 100644
--- a/src/main/java/net/azalealibrary/configuration/property/Property.java
+++ b/src/main/java/net/azalealibrary/configuration/property/Property.java
@@ -33,20 +33,15 @@ public void deserialize(@Nonnull ConfigurationSection configuration) {
Optional.ofNullable(configuration.get(getName())).ifPresent(object -> set(propertyType.deserialize(object)));
}
- @Override
- public boolean equals(Object object) {
- if (object instanceof Property> property) {
- return property.name.equals(name) && property.propertyType.getType().equals(propertyType.getType());
- }
- return super.equals(object);
- }
-
@Override
public String toString() {
return isSet() ? propertyType.print(get()) : "";
}
public static Builder create(PropertyType type, String name, Supplier defaultValue) {
+ if (!name.matches("[a-zA-Z0-9_]+")) {
+ throw new IllegalArgumentException("Property '" + name + "' contains non-alphanumeric characters.");
+ }
return new Builder<>(type, name, defaultValue);
}
diff --git a/src/main/java/net/azalealibrary/configuration/property/PropertyType.java b/src/main/java/net/azalealibrary/configuration/property/PropertyType.java
index 7502e14..9022cdd 100644
--- a/src/main/java/net/azalealibrary/configuration/property/PropertyType.java
+++ b/src/main/java/net/azalealibrary/configuration/property/PropertyType.java
@@ -16,14 +16,14 @@
@SuppressWarnings("unchecked")
public class PropertyType {
- public static final PropertyType STRING = new PropertyType<>(String.class, "text");
+ public static final PropertyType STRING = new PropertyType<>("text");
public static final PropertyType INTEGER = new PropertyType<>(Integer.class) {
@Override
public Integer parse(CommandSender sender, Arguments arguments) {
return Integer.parseInt(arguments.get(0));
}
};
- public static final PropertyType DOUBLE = new PropertyType<>(Double.class, "decimal") {
+ public static final PropertyType DOUBLE = new PropertyType<>("decimal") {
@Override
public Double parse(CommandSender sender, Arguments arguments) {
return Double.parseDouble(arguments.get(0));
@@ -64,7 +64,7 @@ public Vector parse(CommandSender sender, Arguments arguments) {
return new Vector(x, y, z);
}
};
- public static final PropertyType LOCATION = new PropertyType<>(Location.class, "position") {
+ public static final PropertyType LOCATION = new PropertyType<>("position") {
@Override
public List complete(CommandSender sender, Arguments arguments) {
if (sender instanceof Player player) {
@@ -148,20 +148,14 @@ public String print(World object) {
}
};
- private final Class> type;
private final String expected;
public PropertyType(Class> type) {
- this(type, type.getSimpleName());
+ this(type.getSimpleName());
}
- public PropertyType(Class> type, String expected) {
+ public PropertyType(String expected) {
this.expected = expected;
- this.type = type;
- }
-
- public final Class> getType() {
- return type;
}
public final String getExpected() {
@@ -200,8 +194,8 @@ public boolean test(CommandSender sender, Arguments arguments) {
@Override
public boolean equals(Object object) {
- if (object instanceof PropertyType> propertyType) {
- return propertyType.type.equals(type) && propertyType.expected.equals(expected);
+ if (object instanceof PropertyType> property) {
+ return property.expected.equals(expected);
}
return super.equals(object);
}
diff --git a/src/test/java/net/azalealibrary/configuration/AzaleaConfigurationTest.java b/src/test/java/net/azalealibrary/configuration/AzaleaConfigurationTest.java
deleted file mode 100644
index 86ca61c..0000000
--- a/src/test/java/net/azalealibrary/configuration/AzaleaConfigurationTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.azalealibrary.configuration;
-
-import be.seeseemelk.mockbukkit.MockBukkit;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-class AzaleaConfigurationTest {
-
- private AzaleaConfiguration plugin;
-
- @BeforeEach
- public void setUp() {
- MockBukkit.mock();
- plugin = MockBukkit.load(AzaleaConfiguration.class);
- }
-
- @AfterEach
- public void tearDown() {
- MockBukkit.unmock();
- }
-
- @Test
- void onLoad() {
-// plugin.getLogger().log(Level.INFO, "onLoad");
- }
-
- @Test
- void onEnable() {
-// plugin.getLogger().log(Level.INFO, "onEnable");
- }
-
- @Test
- void onDisable() {
-// plugin.getLogger().log(Level.INFO, "onDisable");
- }
-}
\ No newline at end of file