[Tutorial/Beginner] Making configs

Discussion in 'Resources' started by theguynextdoor, Dec 30, 2011.

Thread Status:
Not open for further replies.
  1. Offline


    This is my tutorial for making configuration files. In this tutorials, all code shall be in the form of images, as such that people cannot copy and paste the code without at least having to have typed it out manually. This helps memory retention kiddos!

    Making the actual file (Via code)
    So, how do we make a config. Well to make a blank config file it is rather simply, Just use the saveConfig() method in your onEnable. It should look something like this
    This will create a config file which shall look like...
    So, now we have an empty file, how do we go about adding values? Well let's move onto that now shall we.

    Adding default config values
    So, we've got our config file, but we want some default values to be in there for when server owners load up the plugin for the first time, there are values which they can change and the plugin can use.

    First thing we want to do is make a variable. This variable will point to our config file. The variable will be along the lines of

    FileConfiguration config = getConfig();

    You could, just use getConfig() all the time. However, this is NOT good programming practice. It is not as readable and is unnecessary.

    So now from this config variable, there are 2 main methods involved when adding these default values to our config. The first method is called addDefault. This method takes 2 parameters. A string and an object. The first argument (the string) is the path at which the value (argument 2) shall be in the config. And the second argument is the value to be used as default.

    The second method is a method from the ConfigurationOptions class, but don't worry about that, all you need to know is how to get to the method we want. The method we want is called copyDefault(true). To get to this method, we need to use the options() method from the config variable.

    Here is an example of adding a few variables to our config. In this example I add a default String, int and a boolean to my config.

    This lovely code above will create a config file which looks like this.

    Woo! we have a config with values in it!!1!!one!!.
    However we now have all this code cluttering up our onEnable method. Ideally you want your onEnable method to be as clean as readable as possible. So let's implement a bit of the old modularisation, which is a part of good programming practice.

    All you need to do is create a new method, I called mine initialiseConfig, chuck all your config related code into that and then call this method in your onEnable. Here's one I made earlier

    But, you probably want to get these values to use in your code don't you? I know I would, I'm not holding it against you, so let me show you how that is done.

    Getting values
    So the method to get a value from your config is very simple. You just need to use a method, which name depends on the type of data you want to receive. So, for example, say I want to get my String value from the config. I would then use the method getString, if I want my int value, i use the method getInt. Each of these methods will then take 1 parameter. The argument you pass into these parameters, will be the path at which the value can be found. This shall be the same as you defined in the addDefault method (Note the . still refer to sub paths and are still necessary).

    In my example I actually not only get the values, but I put them into a practical use in the form of an event. See if you can work out what each bit does, and how changing each value will effect the event.

    If you couldn't work out what each value does, despite having my lovely comments in the code, allow me to explain.

    The first line, where I get the boolean, I am checking if the boolean is equal to true. If it is then I proceed with the code inside the if statement, if not then nothing happens. Obviously changing this value will change whether the if statement is true or not.

    The second line is a beautiful for loop. This uses my integer value and is basically repeating the next line a set number of times. This set number of times, will be equal to our integer value from our config.

    The third line is just sending a message to our player, where the message is the string from our config. Changing that will change the message sent.

    Setting values (Via code)
    Note: The example image for this has a fair bit of code, which looks overwhelming, but I assure you it is all basic stuff and is highly ... highly commented.

    The method to set a value is super duper easy. The method is called .. wait for it ... set. That's right, the method is called set and it takes 2 arguments. The first parameter is the path of the value to set. The second is the value to set it to.

    Note that a lot of the following code includes data validation. This is making sure the user enters the right data type for the command.

    The following code is still in the main class.
    Well, here goes nothing. Lots of comments. Don't say I didn't warn you.

    This was quite an overhaul from my old tutorial. If I have missed anything let me know. All the code should work, it has been tested. If you don't understand anything, then make a post in the comments, or PM me, and I shall try to get back to you as soon as I can (No guarantees :p)

    I see a lot of people, namingly newbies, using the following method to get their config file. I don't like this method at all. I even see people recommend/give this method in the plugin dev section. I may not say it to them, but these people get -1 Guy point.

    The method I am talking about is this...

    public void onEnable {
        File file = new File(getDataFolder(), "config.yml");
        if(!file.exists()) {
            try {
            } catch (Exception e) {
    // BLA BLA BLA
    // More unnecessary code here
    This is unnecessary. Why should you even need to make the file and check if it exists, if the getConfig() method and saveConfig() method does all you need? It is unnecessary code on your part handling IO stuff you don't need to.

    It pains me every time I see people use this method. There is literally NO NEED to use this method.
  2. Offline


    Finally, an updated efficient configuration tutorial. This is my new method. Thanks, @theguynextdoor !
    TopGear93 and theguynextdoor like this.
  3. Offline


    What are the differences between FileConfigurations and Configurations? Which method is more efficient or they are just the same?
  4. Offline


    If you are specifically talking about the classes, Configurations is an interface that FileConfigurations implements. Meaning alone, the Configurations class isn't much. If you are talking about the difference between FileConfigurations and YamlConfigurations, FileConfigurations makes a generic config.yml while YamlConfigurations opens more doors for configs like users.yml or <different_file>.yml
  5. Offline


    ok, i m currently using bukkit's Configuration class to store my datas like a flatfile. Any suggestions on that?
    unforgiven5232 likes this.
  6. Offline


    Well, none of my plugins use datastorages, even my private ones. I am making a plugin that will use one, but datastorage is last on my list cause it scares me. I'd recommend if you use anything for storage within bukkit, make a new YamlConfiguration with a different file name. The FileConfiguration class makes it config.yml by default, so that could easily confuse people. But for actual datastorage, if it is small, flatfile works well, large datastorages MySQL or SQLite are good options.
  7. Offline


    well actually, i am currently using
    new Configuration(new File(plugin.getDataFolder(), "data.yml"));
    which will make a file named data.yml under plugin data folder :). The problem i m worrying about is that everytime i fetch some data from the file, i have to load the entire file. I have seen people doing cache or something that load all datas on plugin start and you can easily fetch data in a hashmap. Which method do you prefer?
  8. Offline


    Is there a way to add Comments ?
    pcgamers123 likes this.
  9. Offline


    Not to my knowledge, i think the only way was to make a config.yml and add it to your plugin when you export it or something, and it would have comments, but the comments would get deleted when the config is saved. So until someone has a solution i don't think there are any easy ways to add comments.
  10. Offline


  11. Offline


    What about the lists? like: Boolean lists, String lists, Key lists, Byte lists etc. Would be nice to implement them here :)
  12. Offline

    Sagacious_Zed Bukkit Docs

    Since you had to ask this question, then the tutorial did not really do a good job of teach you how to use the API. It excels because it gives you snippets to follow and examples. Yes, the tutorial shows you what to do in great detail, but here you must instead think how to use certain methods to achieve what you want.

    The instructions for any given List would be like the list example but with the corresponding value in its place.
  13. Offline


    I only said it would be nice to implement them, but whatever.
  14. Offline


    Updated: getting values from config from another class (i dont know how to say it)

    pretty much getting values from your config which is in your main class while you are in your listener class.

    Please comment, for i feel that this may need some more explaining. Which i am glad to do btw on any part of the tutorial.
  15. Offline


    I'm glad you added the section about referencing config variables from another class, that's the part I've had trouble with. :)

    I haven't switched over to the new event system yet, is there anything hugely different when doing so on the old system? I can't seem to get my listener class to see it yet (field not visible).
  16. Offline


    Making the plugin variable from another class with the old event system is the same really. I shall show you an example of it with old system.

    This would be my main class.
    1. public class SnowBallNextDoor extends JavaPlugin {
    3. private final Logger log = Logger.getLogger("Minecraft");
    4. private final SnowballEntityListener entityListener = new SnowballEntityListener(this);
    5. private final SnowballPlayerListener playerListener = new SnowballPlayerListener(this);
    6. private final SnowballBlockListener blockListener = new SnowballBlockListener(this);
    8. @Override
    9. public void onDisable() {
    10. log.info(this.getDescription().getName() + " has been disabled");
    11. }
    13. @Override
    14. public void onEnable() {
    15. log.info(this.getDescription().getName() + " v" + getDescription().getVersion() + " has been enabled");
    17. PluginManager pm = Bukkit.getServer().getPluginManager();
    18. pm.registerEvent(Type.ENTITY_DAMAGE, entityListener, Priority.Normal, this);
    19. pm.registerEvent(Type.PROJECTILE_HIT, entityListener, Priority.Normal, this);
    20. pm.registerEvent(Type.PLAYER_INTERACT, playerListener, Priority.Normal, this);
    21. pm.registerEvent(Type.BLOCK_BREAK, blockListener, Priority.Normal, this);

    And this would be my block listener for example.
    1. public class SnowballBlockListener extends BlockListener {
    2. SnowBallNextDoor plugin;
    4. public SnowballBlockListener(SnowBallNextDoor instance) {
    5. plugin = instance;
    6. }
    8. @Override
    9. public void onBlockBreak(BlockBreakEvent e) {
    11. bla bla bla bla

    Note that in your main class you need
    1. private final SnowballBlockListener blockListener = new SnowballBlockListener(this);

    With the main part being the 'this'
  17. Offline


    You can't add comments, but you can set the header of the file (a major comment for all the file) like that :

    2. getConf().options().header("Example on How to set an header");

    Every time your configuration is saved, the header is rewrite first :)

    Moreover I created a new System to use and configure easily the config file, using a Enum :
    1) the ConfigEnum :
    Every item of the enum have 3 parts :
    1) the "path" in the configuration file
    2) the default value of that path
    3) a description of what for the path exists.

    And of course like every Enum the "name" of the item.
    2. /************************************************************************
    3.  * This file is part of WarpSign.
    4.  *
    5.  * WarpSign is free software: you can redistribute it and/or modify
    6.  * it under the terms of the GNU General Public License as published by
    7.  * the Free Software Foundation, either version 3 of the License, or
    8.  * (at your option) any later version.
    9.  *
    10.  * WarpSign is distributed in the hope that it will be useful,
    11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13.  * GNU General Public License for more details.
    14.  *
    15.  * You should have received a copy of the GNU General Public License
    16.  * along with WarpSign. If not, see <[url]http://www.gnu.org/licenses/>[/url].
    17.  ************************************************************************/
    18. /**
    19.  * @author Balor (aka Antoine Aflalo)
    20.  *
    21.  */
    22. package be.Balor.WarpSign;
    24. import java.util.LinkedHashMap;
    25. import java.util.Map;
    27. import org.bukkit.configuration.ConfigurationSection;
    29. public enum ConfigEnum {
    30. KEYWORD("warpKeyWord", "[ACWarp]", "set the keyword used to recognise a WarpSign.\n "
    31. + "BE CAREFULL if you change it, older WarpSign will be not working."),
    33. "autoComplete", true,
    34. "when typing the name of a world of a warp, if set to true, will autocomplete the Sign."),
    35. WORLDNF(
    36. "worldNotFound", "This World doesn't exists : ",
    37. "Message used when using the autoComplete feature and the World couldn't be found."),
    38. WARPNF(
    39. "warpNotFound", "This Warp doesn't exists : ",
    40. "Message used when using the autoComplete feature and the Warp couldn't be found."),
    41. COLOR(
    42. "useColor", true,
    43. "When set to true, will automatically color the World and Warp name on the sign using the color defined below.");
    45. private final String confVal;
    46. private final Object defaultVal;
    47. private final String description;
    48. private static ConfigurationSection config;
    50. /**
    51.   * @param confVal
    52.   * @param defaultVal
    53.   * @param description
    54.   */
    55. private ConfigEnum(String confVal, Object defaultVal, String description) {
    56. this.confVal = confVal;
    57. this.defaultVal = defaultVal;
    58. this.description = description;
    59. }
    61. public String getString() {
    62. return config.getString(confVal);
    63. }
    65. public int getInt() {
    66. return config.getInt(confVal);
    67. }
    69. public double getDouble() {
    70. return config.getDouble(confVal);
    71. }
    73. public boolean getBoolean() {
    74. return config.getBoolean(confVal);
    75. }
    77. public long getLong() {
    78. return config.getLong(confVal);
    79. }
    80. /**
    81.   * @return the defaultvalues
    82.   */
    83. public static Map<String, Object> getDefaultvalues() {
    84. Map<String, Object> values = new LinkedHashMap<String, Object>();
    85. for (ConfigEnum ce : values())
    86. values.put(ce.confVal, ce.defaultVal);
    87. return values;
    88. }
    90. public static String getHeader() {
    91. StringBuffer buffer = new StringBuffer();
    92. for (ConfigEnum ce : values())
    93. buffer.append(ce.confVal).append("\t:\t").append(ce.description).append(" (Default : ")
    94. .append(ce.defaultVal).append(')').append('\n');
    95. return buffer.toString();
    96. }
    97. /**
    98.   * @param config the config to set
    99.   */
    100. public static void setConfig(ConfigurationSection config) {
    101. ConfigEnum.config = config;
    102. }
    103. }

    2) How to use it on the onEnable event of your Plugin :
    2. public void onEnable() {
    3. FileConfiguration conf = getConfig();
    4. ConfigEnum.setConfig(conf);
    5. conf.addDefaults(ConfigEnum.getDefaultvalues());
    6. conf.options().header(
    7. "This is the configuration file of WarpSign\n" + ConfigEnum.getHeader());
    8. conf.options().copyDefaults(true);
    9. try {
    10. config.save(new File(getDataFolder(), "config.yml"));
    11. } catch (IOException e2) {
    12. e2.printStackTrace();
    13. }
    15. }

    3) Using it in a listener by Example :
    2. /************************************************************************
    3.  * This file is part of WarpSign.
    4.  *
    5.  * WarpSign is free software: you can redistribute it and/or modify
    6.  * it under the terms of the GNU General Public License as published by
    7.  * the Free Software Foundation, either version 3 of the License, or
    8.  * (at your option) any later version.
    9.  *
    10.  * WarpSign is distributed in the hope that it will be useful,
    11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13.  * GNU General Public License for more details.
    14.  *
    15.  * You should have received a copy of the GNU General Public License
    16.  * along with WarpSign. If not, see <[url]http://www.gnu.org/licenses/>[/url].
    17.  ************************************************************************/
    18. package be.Balor.WarpSign.Listeners;
    20. import org.bukkit.block.Sign;
    21. import org.bukkit.event.EventHandler;
    22. import org.bukkit.event.EventPriority;
    23. import org.bukkit.event.Listener;
    24. import org.bukkit.event.block.BlockBreakEvent;
    26. import be.Balor.Manager.Permissions.PermissionManager;
    27. import be.Balor.WarpSign.ConfigEnum;
    29. /**
    30.  * @author Balor (aka Antoine Aflalo)
    31.  *
    32.  */
    33. public class SignListener implements Listener {
    35. @EventHandler(priority = EventPriority.NORMAL)
    36. public void onBlockBreak(BlockBreakEvent event) {
    37. if (event.isCancelled())
    38. return;
    39. if (!(event.getBlock().getState() instanceof Sign))
    40. return;
    41. Sign sign = (Sign) event.getBlock().getState();
    42. if (sign.getLine(0).indexOf(ConfigEnum.KEYWORD.getString()) != 0)
    43. return;
    44. if (!PermissionManager.hasPerm(event.getPlayer(), "admincmd.warpsign.edit"))
    45. event.setCancelled(true);
    47. }
    49. }

    The Idea is quite simple :
    2. ConfigEnum.ENUM_VALUE_YOU_DEFINED.getTYPE();

    Where of course ENUM_VALUE_YOU_DEFINED is the name of the Enum item.
    And TYPE = Int OR String OR Long OR Double.
    Steffion and bigbeno37 like this.
  18. Offline

    Don Redhorse

    Nice one Dark_Balor similar to my approach.. need to work more on it..

    didn't know you were back at coding..
  19. Offline


    I never left. I just didn't had the time to maintain my plugins and adding new functionality ... Thanks for taking the Tomb Plugin :)

    Right now I just maintain VirtualChest and work on AdminCmd (quite taking a lot of time ...). This part of the code is for an addon of AdminCmd.

    Before I forgot here is the output (the config file) of the code :
    # This is the configuration file of WarpSign
    # warpKeyWord    :    set the keyword used to recognise a WarpSign.
    #  BE CAREFULL if you change it, older WarpSign will be not working. (Default : [ACWarp])
    # autoComplete    :    when typing the name of a world of a warp, if set to true, will autocomplete the Sign. (Default : true)
    # worldNotFound    :    Message used when using the autoComplete feature and the World couldn't be found. (Default : This World doesn't exists : )
    # warpNotFound    :    Message used when using the autoComplete feature and the Warp couldn't be found. (Default : This Warp doesn't exists : )
    # useColor    :    When set to true, will automatically color the World and Warp name on the sign using the color defined below. (Default : true)
    # wordColor    :    This color will be use for colouring the Word's name on the sign. (Default : &6)
    # warpColor    :    This color will be use for colouring the Warp's name on the sign. (Default : &a)
    # useCount    :    When set to true, the last line of the sign is used to count the number of teleportation done using the sign. (Default : true)
    # countMessage    :    When Count is set to true, this message will be used to display the teleport count. (Default : &cCount: &d)
    # teleportMessage    :    Teleport message used when successfully teleported to the Warp Point. (Default : &aTeleported successfully to &f)
    warpKeyWord: '[ACWarp]'
    autoComplete: true
    worldNotFound: 'This World doesn''t exists : '
    warpNotFound: 'This Warp doesn''t exists : '
    useColor: true
    wordColor: '&6'
    warpColor: '&a'
    useCount: true
    countMessage: '&cCount: &d'
    teleportMessage: '&aTeleported successfully to &f'
  20. Offline

    Don Redhorse

    well I hope to get somewhere further today with my new concept.

    the problem really is to make it easy for somebody else to use, my aim is similar to this:

    # TheMonkeyPack 0.1 by [Don Redhorse]
    # Configuration File for TheMonkeyPack.
    # For detailed assistance please visit: http://dev.bukkit.org/server-mods/monkey-pack/
    #------- Default Configuration
    # Configuration Version
    configVer: '1.0'
    # Error Log Enabled
    # Enable logging to server console
    # Warning and Severe will still be logged.
    errorLogEnabled: true
    # Debug Log Enabled
    # Enable more logging.. could be messy!
    DebugLogEnabled: true
    # Check for Update
    # Will check if there is a new version of the plugin out.
    checkForUpdate: true
    # Auto Update Config
    # This will overwrite any changes outside the configuration parameters!
    autoUpdateConfig: false
    # Save Config
    # This will overwrite any changes outside the configuration parameters!
    # Only needed if you use ingame commands to change the configuration.
    saveConfig: false
    # ------- Translation Features
    # Almost everything player visible (except admin commands) can be translated!
    # Please change to your liking and use the following variables
    # %perm = permission, %cmd = command, %Description = command description
    # NOTE: You need to use '' if you want to use ' in this text!
    # Message displayed when the permission is denied to use that command
    permDenied: 'You need the permission %perm to use the %cmd command which %Description !'
    # Message displayed when the wrong syntax for that command was used
    wrongSyntax: 'You used the wrong syntax for the command %cmd'
    # Message displayed when the right syntax for that command was used
    rightSyntax: 'The right syntax for this command is '
    # Message displayed when the explanation of the command is shown
    allowsYouTo: 'which allows you to %Description.'
    # Message displayed when the example of the command is shown
    example: 'An example for the command is '
    #-------- Module Configuration
    # Enable the different modules here or via
    # /mtp enable [MODULENAME]
    # After that you need to reload the server or use
    # /mtp reload
    # to create the config files for the different modules
    # So you still need to configure THEM!
    #-------- Module [AFK Handler] --------
    # Kick, Announce, GOD mode when AFK
    enableRARP: false
    #-------- Module [HelloWorld] --------
    # Announce which world you entered
    enableHelloWorld: false
    #-------- Module [Lampstone] --------
    # Switch between different blocks between day and night
    enableLampstone: false
    #-------- Module [Wurkit] --------
    # Earn Money when you build or destroy stuff
    enableGetPayed: false
    #-------- Module [Kits] --------
    # Give out kits to your players
    enableKits: true
  21. Offline


    A class that would let you make a config like that, that you could just drop-into your project would be a dream come true. :)
  22. Offline

    Don Redhorse

    or a nightmare.... at least for me coding it... I think it will come down to several classes though... one for the config (an enum similar to the stuff Dark_Balor posted), one for the messages (also an enum to support translation) and than one class which extends a base class in which you could define other stuff.

    major benefit of this would be that almost everything would be automatic, loading, saving, reloading, updating etc.. you just needed to call the methods.

    My major problem is that I'm not that good at coding... so I probably do it in an arkward way... wonder if I should just let people handle the creating of the config by making a call per line to a method or similar...


    perhaps the better way..
  23. Offline


    I'm still having trouble getting values from my config, I can tell that it's a simple issue but thanks to my extreme noobishness and trying to learn in the middle of this event system conversion, it's throwing me off. :)

    Still using the old system, and trying to use guynextdoor's methods. Since I'm still extending JavaPlugin, whenever I try to use config.getInt("blah.blah") for example, Eclipse is complaining under config: "The field JavaPlugin.config is not visible".

    So when I'm declaring config at the top of my onEnable here:
    final FileConfiguration config = this.getConfig();
    My guess is that I need to reference config from somewhere other than "this"?
  24. Offline

    Sagacious_Zed Bukkit Docs

    Darkhand81 make sure it is inside onEnable. If not, since technically JavaPlugin already has an config field, then you should choose a different name. fyi the private config variable is what you get when you call getConfig().
  25. Offline


    Ah ha! I wasn't aware of the already existing field. Thanks!

    I still can't access it outside of the class though (or even outside the onEnable method). Do I need some sort of getter method to access it outside of onEnable?
  26. Offline

    Don Redhorse

    well you need to declare the variable outside of onEnable() normaly after your first { and before any method.

    if you do it the way you described that variable is I think called a field(?) (doesn't matter really) and only accessible in that method.

    so the best way to declare it would be

    private FileConfiguration config;

    than in onEnable()

    config = this.getConfig();

    and afterwards you would have a getter

    public FileConfiguration getConfig(){
    return config;
  27. Offline

    Sagacious_Zed Bukkit Docs

    I disagree, that is not the best way to do it. I would put the above example down as what NOT to do. When you inherit JavaPlugin you inherited its getConfig() method, if you override it bad things happen if you are not aware of it.

    Something like this as the main class should work well enough.
    1. public PluginMain extends JavaPlugin {
    2. // JavaPlugin requires you to implement two methods onEnable and onDisable
    3. public void onEnable() {
    4. final FileConfiguration config = this.getConfig();
    5. config.getString("Hello.World");
    6. // more things to enable
    7. }
    9. public void onDisable() {
    10. }
    11. }

    If you need to get the the configObject outside of this class, you can call this classes getConfig() method.
  28. Offline


    That's what's throwing me for some reason, do you happen to have an example?
  29. Offline

    Don Redhorse

    where was I overriding it? (me <== noob)

    Problem with the above is that you need to do

    private PluginName plugin = PluginName.getInstance(); or similar and
    private FileConfiguration config = plugin.getConfig();

    in the other class to be able to use it (or create a static getter) with


    which is honestly stupid..

    by far better would be to just get all values from the config in one class and make them accesable via getters and setters from other classes.

    at least I think
  30. Offline

    Sagacious_Zed Bukkit Docs

    Don Redhorse
    Anytime you define a method with the same name and signature as that of a parent class you override the method.
    Anytime you define a method with the same name but different signature you over load the method.

    In general you should not assign the returned value from getConfig() to a class field. The short reason is that getConfig does not have to return the same object every time it is called. And it's proper encapsulation to be passing plugin into a class that needs to know about it.

    And yes, it's a completely valid approach to create a class with methods that always grab a particular value, but it can also be very verbose to write. So often i take the mid ground approach, i define an enum with the constants i am using as keys in my yaml.
Thread Status:
Not open for further replies.

Share This Page