Skip to content

TownyAdvanced/CommentedConfiguration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CommentedConfiguration

A yaml configuration system that supports comments, automatic editing of existing config comments, automatic adding of new config nodes.

Importing CommentedConfiguration into your project

Maven:

  <repositories>
    <repository>
      <id>glaremasters repo</id>
      <url>https://repo.glaremasters.me/repository/towny/</url>
    </repository>
  </repositories>
  <dependency>
    <groupId>io.github.townyadvanced.commentedconfiguration</groupId>
    <artifactId>CommentedConfiguration</artifactId>
    <version>1.0.0</version>
  </dependency>

Gradle:

repositories {
    maven {
        name = 'glaremasters repo'
        url = 'https://repo.glaremasters.me/repository/towny/'
    }

dependencies {
    compileOnly 'io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.0'
}

Usage

CommentedConfiguration can be used via the included Settings class, or using your own settings-replacement similar to what Towny uses: settings, enum.

To use the Settings you need to provide three things:

  • A path where your file will be saved.
  • A Logger or Plugin instance for CommentedConfiguration to use when it needs to log information.
  • A List of CommentedNodes which will be used to create your config.

Example Nodes Class from which the Settings examples below grabs the CommentedNodes list using #getAllNodes.

The included Settings class comes with the following constructors:

/**
* Creates a new CommentedSettings instance that makes use of CommentedConfiguration.
*
* @param configPath The path to the configuration file.
* @param plugin The Plugin to get the logger from.
* @param defaultNodes The default node values to add to the configuration.
*/
public Settings(@NotNull Path configPath, @NotNull Plugin plugin, @Nullable List<CommentedNode> defaultNodes) {
this.config = new CommentedConfiguration(configPath, plugin);
this.configPath = configPath;
this.defaultNodes = defaultNodes;
}
/**
* Creates a new CommentedSettings instance that makes use of CommentedConfiguration.
*
* @param configPath The path to the configuration file.
* @param logger The Logger to use for error messages.
* @param defaultNodes The default node values to add to the configuration.
*/
public Settings(@NotNull Path configPath, @Nullable Logger logger, @Nullable List<CommentedNode> defaultNodes) {
this.config = new CommentedConfiguration(configPath, logger);
this.configPath = configPath;
this.defaultNodes = defaultNodes;
}

Example initialization in your plugin Settings class:

private final File configFile = new File("path/to/config.yml"); // The destination you want your config.yml saved to.
private Settings settings;

// Settings initialized with a supplied logger & a list of CommentedNodes.
settings = new Settings(configFile.toPath(), Logger.getLogger("YourLoggerNameHere"), TestNodes.getAllNodes());

// Settings initialized with a supplied plugin & a list of CommentedNodes.
settings = new Settings(configFile.toPath(), yourPluginInstance, TestNodes.getAllNodes());

After which, you can load and then save your file to the server using:

settings.load();
settings.save();

From that point you can get your config file's values using the following methods, opting to use generic or typed lookups:

/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @return The value of the node.
*/
public Object get(@NotNull ValueNode node) {
return config.get(node.getPath(), node.getDefaultValue());
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @param type The type of the node value.
* @return The value of the node.
* @param <T> The type of the node value.
*/
public <T> T get(@NotNull ValueNode node, Class<T> type) {
return config.getObject(node.getPath(), type, (T) node.getDefaultValue());
}
/**
* Gets the value of a node, if the node has a default value, it will be returned if the node is not found.
*
* @param node The node to get the value of.
* @return The value of the node.
* @param <T> The type of the node value.
*/
public <T> T get(@NotNull TypedValueNode<T> node) {
return config.getObject(node.getPath(), node.getType(), node.getDefaultValue());
}

You can also save settings back to the config using the following methods, just remember to save your settings field afterwards using settings.save();

/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param node The node to set the value of.
* @param value The value to set.
*/
public void set(@NotNull ValueNode node, Object value) {
config.set(node.getPath(), value);
}
/**
* Sets the value of a node, if the validator is not null, it will be tested first.
*
* @param node The node to set the value of.
* @param value The value to set.
* @param <T> The type of the node value.
*/
public <T> void set(@NotNull TypedValueNode<T> node, T value) {
config.set(node.getPath(), value);
}

Further example

Click to view

Main

package org.example;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.logging.Logger;

import io.github.townyadvanced.commentedconfiguration.setting.Settings;

public class Main {
    public static void main(String[] args) {
        final Path file = Path.of("/home/ben10/Desktop/config.yml");
        final Settings settings = new Settings(file, Logger.getLogger("TEST"), TestNodes.getAllNodes());
        if (!settings.load()) {
            System.out.println("Failed to load config");
            return;
        }
        System.out.println("Loaded config");
        System.out.println(settings.get(TestNodes.BOOLEAN_NODE));
        System.out.println(settings.get(TestNodes.STRING_NODE));
        System.out.println(settings.get(TestNodes.LOCATION_NODE));
        settings.save();
        System.out.println("Saved config");

        final Path enumFile = Path.of("/home/ben10/Desktop/enumconfig.yml");
        final Settings enumSettings = new Settings(enumFile, Logger.getLogger("ENUMTEST"), Arrays.asList(TestEnumNodes.values()));
        if (!enumSettings.load()) {
            System.out.println("Failed to load enumconfig");
            return;
        }
        System.out.println("Loaded enumconfig");
        System.out.println(enumSettings.get(TestEnumNodes.TEST_BOOLEAN));
        System.out.println(enumSettings.get(TestEnumNodes.TEST_STRING));
        System.out.println(enumSettings.get(TestEnumNodes.TEST_LOCATION));
        enumSettings.save();
        System.out.println("Saved enumconfig");
    }
}

TestEnumNodes

package org.example;

import io.github.townyadvanced.commentedconfiguration.setting.ValueNode;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public enum TestEnumNodes implements ValueNode {
    TEST_BOOLEAN(
            "test.boolean",
            true,
            new String[] {"# This is a test boolean.", "# It is true by default."}
    ),
    TEST_STRING(
            "test.string",
            "Hello, world!",
            new String[] {"# This is a test string.", "# It is \"Hello, world!\" by default."}
    ),
    TEST_LOCATION(
            "test.location",
            new Location(null, 0, 0, 0),
            new String[] {"# This is a test location.", "# It is (0, 0, 0) by default."}
    ),
    ;

    private final String path;
    private final Object defaultValue;
    private final String[] comments;

    TestEnumNodes(String path, Object defaultValue, String[] comments) {
        this.path = path;
        this.defaultValue = defaultValue;
        this.comments = comments;
    }

    @Override
    public @NotNull String getPath() {
        return path;
    }

    @Override
    public @Nullable Object getDefaultValue() {
        return defaultValue;
    }

    @Override
    public @NotNull String[] getComments() {
        return comments;
    }
}

TestNodes

package org.example;

import java.util.ArrayList;
import java.util.List;

import io.github.townyadvanced.commentedconfiguration.setting.CommentedNode;
import io.github.townyadvanced.commentedconfiguration.setting.SimpleNode;
import io.github.townyadvanced.commentedconfiguration.setting.TypedValueNode;
import org.bukkit.Location;

public class TestNodes {
    private static final List<CommentedNode> nodes = new ArrayList<>();

    private static <T> TypedValueNode<T> node(TypedValueNode<T> node) {
        nodes.add(node);
        return node;
    }

    public static final TypedValueNode<Boolean> BOOLEAN_NODE = node(SimpleNode.builder("test.boolean", Boolean.class)
            .defaultValue(true)
            .comment("This is a boolean")
            .build());

    public static final TypedValueNode<String> STRING_NODE = node(SimpleNode.builder("test.string", String.class)
            .defaultValue("default")
            .comment("This is a string")
            .build());

    public static final TypedValueNode<Location> LOCATION_NODE = node(SimpleNode.builder("test.location", Location.class)
            .defaultValue(new Location(null, 0, 0, 0))
            .comment("This is a location")
            .build());

    public static List<CommentedNode> getAllNodes() {
        return nodes;
    }
}

Converting Existing Configs To CommentedConfiguration

@ipiepiepie has created a python script that will convert configuration files into CommentedConfigurations.

It is available on their CommentedConfigurationMigrator repo, make sure you check it out if you aren't starting from scratch.

History

CommentedConfiguration goes waaay back to the original days of Bukkit plugins. Originally devised by dumptruckman who used it in his PluginBase, it was added into Towny in August of 2011. It was maintained over the years in the Towny codebase, receiving a number of updates that kept it working as Bukkit developed. Even after Bukkit's native yaml configuration received the ability to handle comments in late 2021, the CommentedConfiguration system is still superior for its ability to update the config's existing comments as your plugin updates.