[Tutorial] Working with Configuration Files

Discussion in 'Spigot Plugin Development' started by Bolt, May 9, 2015.

  1. Hi there! So I'll be making a tutorial for how to work with configurations. I know there are quite a few out there but I decided to make my own with my different methods for reading and writing to configuration files and how to work with multiple files. I'll be posting it here for a while but if this get good reviews, I'll put this in the wiki.

    First of all, what exactly is a config file for?
    As you develop, you will come across many instances wherein you will have to store data. A lot of the time, you can store this data in an object such as a HashMap or an ArrayList. So why use configuration files? The reason for this is that when the server is closed or restarts, it recreates everything and all the data you stored would have been lost. This is because objects such as those are stored in the virtual memory. In other words, just as easily as they were created, they are also destroyed.

    Now this is where files come in handy. Files are a way of saving data in a form that won't get deleted after your program is terminated.This is because files are no longer stored in virtual memory but rather, on your actual storage disk. You can use this for storing information such as player balances, nicknames, and all sorts of data that you want to keep even after the server restarts.

    Let's get started.

    I have two ways of creating configuration files which I will show you today. The first, simpler one, is more suitable for when you're making quick plugins that only require single configuration files.

    The creation of the configuration file:
    Code (Java):
    private void createConfig() {
            try {
                if (!getDataFolder().exists()) {
                    getDataFolder().mkdirs();
                }
                File file = new File(getDataFolder(), "config.yml");
                if (!file.exists()) {
                    getLogger().info("Config.yml not found, creating!");
                    saveDefaultConfig();
                } else {
                    getLogger().info("Config.yml found, loading!");
                }
            } catch (Exception e) {
                e.printStackTrace();

            }

        }
    This method essentially creates the configuration file itself. It is important that you call this method in you onEnable method so that before anything in your plugin tries to read from the file, you already know that the file is there. I will now explain what the code does:

    The first part:
    Code (Java):
    if (!getDataFolder().exists()) {
                    getDataFolder().mkdirs();
                }
    This is a check to see if your plugin folder already exists. The way Spigot/Bukkit manages plugin information is that each plugin has its own 'data folder'. These are the folders you see in your server's plugin folder named after the plugins containing important information such as their own individual configuration files. To get the path of this folder, you call the method getDataFolder() to return the File which is a path to what the server has designated as your plugin's Data Folder. The 'if' statement is checking whether or not the folder exists and if it doesn't, then it calls the mkdirs() method which basically creates the directory.

    The next part:
    Code (Java):
    File file = new File(getDataFolder(), "config.yml");
                if (!file.exists()) {
                    getLogger().info("Config.yml not found, creating!");
                    saveDefaultConfig();
                } else {
                    getLogger().info("Config.yml found, loading!");
                }
    This where you declare your config file itself. To do this, you create a File object and construct it with the parameters 'getDataFolder()' and "config.yml". Like I mentioned earlier, the getDataFolder() method returns a file which is the directory of your data folder. Now by putting it as the first parameter, it is telling your constructor that it will create a file named "config.yml" in the directory which is named by getDataFolder(). Now that file isn't actually stored yet in your storage. It is still in virtual memory. The next 'if' statement checks whether or not the file exists and if it doesn't it creates it and tells your plugin that this file is going to be 'my' config file. You should call saveDefaultConfig() to tell that this is how my default config file will be like.

    This is essentially all you need to create a quick config file but remember to call it in your onEnable method to make sure that you have a config ready before anything else happens.

    Then, we tackle the next issue:
    We have a config file. What do we do with it and how?
    To read and write to the config using the above method, we call the getConfig() method. However, if you will be calling getConfig() outside of your main class, you should use the main class's instance. If you do not know how to make instances, I suggest you check some of the other short guides on how to make one. Once you have an instance, simply use that instance and call getConfig() from it.
    Supposing my main class was called Plugin, and my instance was called 'instance', I could get the config like this:
    Code (Java):
    Plugin.instance.getConfig();
    // or if you are using a getInstance() method:
    Plugin.getInstance().getConfig();
    Now that you have the config, you can read and write to it using its different getter and setter methods. An example would be like:
    Code (Java):
    // Reading from the config
    String name = Plugin.getInstance().getConfig().getString("player-name");

    // Writing to the config
    Plugin.getInstance().getConfig().set("player-name", name);
    What is it exactly? The "player-name" is your path in the config. If you've seen other configuration files, you'll notice that they take the format of "label: value". To access the value of a particular path, you can use its name. However, you'll also notice that there are sometimes "sub-paths" wherein there are labels that belong under another label.

    Code (YAML):
    player-name: Steve

    player
    :
      time
    :
        join
    : 6:00pm
    To access the value of something that's a sub-path, you can simply use '.' to indicate a lower level like so:
    Code (Java):
    // Reading from the config
    String time = Plugin.getInstance().getConfig().getString("player.time.join");

    // Writing to the config
    Plugin.getInstance().getConfig().set("player.time.join", time);
    The plugin will read the '.' as an indicator that "Oh! I should check the sub-path."
    Note that although I used a String in the getting and setting examples, you can use all sorts of different types as well. For the getters, there exists getInt(), getBoolean(), getList(), and many more. For the setters, it simply takes in the path as the first parameter and an Object as the second. This means that you can set basically any Object.

    An important thing to note, however, is that after you read/write to a configuration file, you should always remember to save the data if you want it to be saved to the file. To do this, you should do :
    Code (Java):
    Plugin.instance.saveConfig();
    // or
    Plugin.getInstance().saveConfig();
    Configuration has all sorts of fun tricks and tools that you can use to make the best plugin you can make. Use it properly and it can be one of your most powerful assets.

    Part 2 : Working with multiple configuration files
    *Coming Soon*
     
    #1 Bolt, May 9, 2015
    Last edited: May 9, 2015
    • Useful Useful x 9
    • Like Like x 1
    • Informative Informative x 1
  2. Sudzzy

    Patron

    For the first part -
    saveDefaultConfig()
     
    • Like Like x 1
    • Winner Winner x 1
    • Useful Useful x 1
  3. @Sudzzy Ok thanks for the reminder! I added it along with a reminder to call saveConfig() after reading/writing to the config file.
     
  4. Serializator

    Supporter

    As far as I'm concerned Spigot will automatically generate a config.yml file, creating it yourself is quite useless and a waste of time.
     
    • Informative Informative x 1
  5. if you call saveDefaultConfig
     
  6. Serializator

    Supporter

    It was meant as an addition to the comment of @Sudzzy, forgot to quote it.
     
  7. @Bolt now do it without introducing a global state.
     
  8. Exactly.
     
  9. clip

    Benefactor

    You should also show the alternative to storing a config.yml in your plugin.jar and explain how to create a config from your plugin its self:

    Code (Text):
        private void loadDefaultConfigFile() {
           
            FileConfiguration c = getConfig();
           
            c.options().header("PluginName configuration file");
           
            c.addDefault("some.config.option", "some value");
           
            c.options().copyDefaults(true);
           
            saveConfig();
           
            reloadConfig();
        }
     
    • Agree Agree x 1
  10. Just what I needed! I appreciate your effort for making this. Awesome job :)
     
  11. ok someone please explain, is this for BungeeCord or a Spigot plugin like bukkit, because if its for a regular spigot plugin you guys have made it hard enough to confuse me xD
    please someone explain me how to create a file in a BungeeCord plugin , thanks
     
  12. This was created to focus more on regular spigot plugins but the concept can be used to make configs for Bungeecord plugins as well since the concept is quite similar to the one being used for Bungeecord.
     
    • Like Like x 1
  13. I can't understand how I can create a folder with a custom name like "Lang" with its internal file with custom names; like "ita.yml" and "ing.yml" where through the main configuration file choose the language, if on "lang:" there is "ita" it will send the player the message in "ita.yml" if instead there is is "eng" will read the messages in the "eng.yml" file, what can I do?
    Thanks in advance!

    Inviato dal mio W-P311-EEA utilizzando Tapatalk
     
  14. You would just need to make a File for the folder and your YML. Have a method to create the folder and then the file (Do not make the file before the folder) then you can just grab the class, get the FileConfiguration set what you'd like inside the config and then save it.

    Example:
    Code (Text):

    public class Config {

        private File folder;
        private File file;
        private FileConfiguration fileConfiguration;

        private Permission plugin;

        public Config() {
            //Grab our main class instance
            this.plugin = Permission.getInstance();
     
            //This would be your folder, we grab the data folder, and then inside of that we
            //create the folder with a name of your choosing
     
            //OTHER NOTE: I think you can just do (plugin.getDataFolder() + "/lang"); without the need
            //for a file separator
            this.folder = new File(plugin.getDataFolder() + File.separator + "lang");
     
            //This would be your custom named YML file, you can name this whatever you'd like
            //Be sure to put folder, and not plugin.getDataFolder(); or it will not create inside
            //the folder we made above
            this.file = new File(folder, "english.yml");
            this.fileConfiguration = YamlConfiguration.loadConfiguration(file);
        }
     
        //This will re-create the folder, and YML files if they do not exist
        public void createFile() {
            //If the folder does not exist, we will mkdir it (aka create the folder)
            if (!folder.exists()) folder.mkdir();
     
            //Here we check if the file exists
            if (!file.exists()) {
                try {
                    //If it doesn't we try and create the new file
                    file.createNewFile();

                   //If you did not know you can set default things in the YML File
                   fileConfiguration.set("Message", "this is a message");

                   //And then save them using:
                   fileConfiguration.save(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //Here we can simply grab the FileConfiguration
        public FileConfiguration getConfig() {
            return fileConfiguration;
        }

        //And a simply method to save all of the data you may put in
        public void save() {
            try {
                fileConfiguration.save(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    Outside the class you can then do:
    Config config = new Config();
    config.getConfig().set();
    config.save();
    etc..
     

    I am not sure how most plugins go about this, but I would just give ever user a preference option that get's stored in a YML file, then you can grab it and check what language they would prefer and then send them messages accordingly to the language they want.
     
    #15 Willim, Apr 30, 2020
    Last edited: Apr 30, 2020
  15. Please don't necro post.
    Information about what necro posting is, is here.
     
  16. This thread is 5 year old..
    There is a wiki page about this subject.
     
  17. Good tutorial :)
     
    • Agree Agree x 1