How to make an advanced configuration file

From Minecraft Forge
Jump to: navigation, search

Advanced Configurations are a neat and easy to use feature provided in the Minecraft Forge. It allows you to create and use a property file while having minimal knowledge of java and its FileIO methods and classes. Unlike other Property File APIs, the Forge Advanced Configuration class allows for custom comments for each property, as well as categories for various properties. This results in Advanced Configurations to be easily read and edited by laymen and reduces the number of configuration related errors and crashes.

Contents

SetUp

Before doing anything regarding a Configuration, make sure you have something that's already working made. For this wiki tutorial, I will be using a dummy mod that I created for this purpose. Here is the source code for its mod. For demonstration purposes, we have an item and a block.


Dummy.java

package mod.dummy;

import net.minecraft.src.*;
import cpw.mods.fml.common.*;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.*;
/* +Other imports */

@Mod( modid = "Dummy", name="Dummy", version="1.0")
public class Dummy
{
        @PreInit
        public void preInit(FMLPreInitializationEvent event) {

        }

        @Init
        public void load(FMLInitializationEvent event)
        {
                // where 200 is the BlockID I want to assign it, and 5 is the texture.
                randomBlock = (new RandomBlock(200, 5))
                                .setHardness(1.5F)
                                .setResistance(10.0F)
                                .setStepSound(Block.soundStoneFootstep)
                                .setBlockName("Random Block");

                // where 20000 is the ItemID I want to assign it, and 2 is the texture.
                randomItem = (new RandomItem(20000, 2));

                // This is a boolean that can control some part of a mod - ore generation, allowing an item,
                //   or something else.
                someConfigFlag = false;
        }
       
        @PostInit
        public void postInit(FMLPostInitializationEvent event) {
               
        }

        public static Block randomBlock;
        public static Item  randomItem;
        public static boolean someConfigFlag;
}

This is a bare-bones mod. The Block is created as "public static" but it is not set to anything. The block is formally "initialized" in the load() method. there it is assigned the properties of have 200 as its blockID, and all the other properties set afterwards.

Importing Necessary Classes

The first thing we need to do, is import the Forge Configuration class. we do that by adding a single line to the top of our file.

import net.minecraftforge.common.Configuration;

this line of code makes the Configuration class available for us to use in our mod.


Our mod now looks like this.

package mod.dummy;

import net.minecraft.src.*;
import cpw.mods.fml.common.*;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.*;
/* +Other imports */
import net.minecraftforge.common.Configuration;

@Mod( modid = "Dummy", name="Dummy", version="1.0")
public class Dummy
{
        @PreInit
        public void preInit(FMLPreInitializationEvent event) {

        }

        @Init
        public void load(FMLInitializationEvent event)
        {
                // where 200 is the BlockID I want to assign it, and 5 is the texture.
                randomBlock = (new RandomBlock(200, 5))
                                .setHardness(1.5F)
                                .setResistance(10.0F)
                                .setStepSound(Block.soundStoneFootstep)
                                .setBlockName("Random Block");

                // where 20000 is the ItemID I want to assign it, and 2 is the texture.
                randomItem = (new RandomItem(20000, 2));

                // This is a boolean that can control some part of a mod - ore generation, allowing an item,
                //   or something else.
                someConfigFlag = false;
        }
       
        @PostInit
        public void postInit(FMLPostInitializationEvent event) {
               
        }

        public static Block randomBlock;
        public static Item  randomItem;
        public static boolean someConfigFlag;
}


Creating your Configuration Object

Now that all of our Imports are taken care of, we can begin to actually create our configuration file. The 1st thing that is necessary, is to "instantiate" our Configuration. Since we need to load the configuration before initializing the block in order to set the id, we will use the preInit method. The
getSuggestedConfigurationFile()
of the FMLPreInitializationEvent object will conveniently provide a File for the configuration based on the modid.
        @PreInit
        public void preInit(FMLPreInitializationEvent event) {
                // you will be able to find the config file in .minecraft/config/ and it will be named Dummy.cfg
                // here our Configuration has been instantiated, and saved under the name "config"
                Configuration config = new Configuration(event.getSuggestedConfigurationFile());
        }

Loading and Saving the Configuration

Now that we have our Configuration created, we can begin to use it. the very first thing any configuration should do, is load itself from the file on your computer. This is done by using the Configurations load() method.

config.load();

Of course if you can load from a file, you can also save to it. this is done with the Configurations save() method.

config.save();

After incorporating these save() and load() methods, our mod's preInit method should look like this...

        @PreInit
        public void preInit(FMLPreInitializationEvent event) {
                // you will be able to find the config file in .minecraft/config/ and it will be named Dummy.cfg
                // here our Configuration has been instantiated, and saved under the name "config"
                // If the file doesn't already exist, it will be created.
                Configuration config = new Configuration(event.getSuggestedConfigurationFile());

                // loading the configuration from its file
                config.load();

                // saving the configuration to its file
                config.save();
        }

Basic Property Creation and Usage

But why would you save a file without changing anything in it? This is where the real properties are set. The Configuration class adds 3 methods to aid in the creation of the actual properties. They are in order of ease of use, and automation. that means the 1st one will be very easy to use, the Configuration will have done much of the work for you. However this also doesn't give you much control over what is done. The second-level ones, only do a little bit for you, while you have control over the rest. The 3rd level methods require the most input from you, and give you a great deal of control over what the property contains.


This 1st and easiest method to is to create a property for a Block or Item ID.

                // the NameOfProperty is a String, and the defaultID is an int or Integer
                config.getBlock(NameOfProperty, defaultID).getInt();
                //example
                int randomBlockID = config.getBlock("RandomBlock", 200).getInt();

                int randomItemID = config.getItem("RandomItem", 20000).getInt();

As you can see, all that is required is a name for your property, and an ID to be used as a default if the property doesn't exist yet. What this method does behind the scenes however, is a bit more complicated. It internally calls the second-level method with most of your provided information, and does some other stuff as well. This method specifically tries to do some AI and dynamic ID detection so that BlockID conflicts are minimized. It also ensures that properties created using this method are placed in the Blocks category. Despite being the easiest to use, this method still requires some extra work on the your part, getting the output as an int at the end. If that part at the end of the line was omitted (the part with getInt();) then the output would be of the Property type. Dealing with the Property would require an additional import, and would be rather useless. However some thing can only be done after grabbing the output as a Property, and that will explained in a later section. *see #Using_Comments

The second-level methods require a bit more information from you, but are still quite easy to use. The major difference is that you must specify a category to get

                // the NameOfProperty is a String, the Catagory is a String, and the DefaultValue is an boolean (true or false).
                config.get(Category, NameOfProperty, DefaultValue).getBoolean(DefaultValue);

                // the NameOfProperty is a String, the Catagory is a String, and the DefaultValue is an int or Integer.
                config.get(Category, NameOfProperty, DefaultValue).getInt();

                //examples
                int someBlockID = config.get(Configuration.CATEGORY_BLOCK, "someBlockID", 323).getInt();

                boolean isThisTrue = config.get(Configuration.CATEGORY_GENERAL, "IsThisTrue", true).getBoolean(true);

                int someItemID = config.get(Configuration.CATEGORY_ITEM, "someItemID", 9001).getInt();

As you can see, these methods are not much different from the 1st level method, just they require a teeny bit more information, but give you a bit more control as well. The new additions in these second level methods are the Category parameters, and the addition of the boolean version of the method. The only limitation by these methods is that your types must be either int or boolean properties.


The third level method is the one that affords the most control.

                // the NameOfProperty is a String, the Catagory is a String, and the DefaultValue is String
                config.getOrCreateProperty(NameOfProperty, Category, DefaultValue).value;
               
                //examples
                String someString = config.getOrCreateProperty("SomeString", Configuration.CATEGORY_GENERAL, "nothing").value;
               
                //advanced usage examples
                int someInteger = Integer.parseInt(config.getOrCreateProperty("SomeInteger", Configuration.CATEGORY_GENERAL, ""+100).value);
                float someFloat = Float.parseFloat(config.getOrCreateProperty("PI", Configuration.CATEGORY_GENERAL, ""+3.14).value);

As you can see here, the third level method is only a teeny bit more complicated than the the second level ones. In fact, it could easily be used just like the second level ones in the sense that it is simply a String version. However, you can see in the advanced usage examples, that String can be parsed into a number of other values. The limit is only on your imagination and skill.

Using Comments

The first thing we need to do is import the Property type.

import net.minecraft.src.forge.Property;


Property objects provide much more control over individual properties within the configuration file. We will use a property object to add a comment to a new property.

                // Notice there is nothing that gets the value of this property so the expression results in a Property object.
                Property someProperty = config.get(Configuration.CATEGORY_GENERAL, "SomeConfigString", "nothing");
               
                // Here we add a comment to our new property.
                someProperty.comment = "This value can be read as a string!";
               
                String someConfigString = someProperty.value;
                // This could also be:
                // int someInt = someProperty.getInt();
                // boolean someBoolean = someProperty.getBoolean(true);

Property objects allow us to add comments to properties, check if the property was in the loaded file, etc. They are very useful when creating more complex configuration files.

Completed Dummy Mod

package mod.dummy;

import net.minecraft.src.*;
import cpw.mods.fml.common.*;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.*;
/* +Other imports */
import net.minecraftforge.common.Configuration;
import net.minecraft.src.forge.Property;

@Mod( modid = "Dummy", name="Dummy", version="1.0")
public class Dummy
{
        @PreInit
        public void preInit(FMLPreInitializationEvent event) {
                Configuration config = new Configuration(event.getSuggestedConfigurationFile());

                config.load();

                int randomBlockID = config.getBlock("RandomBlock", 200).getInt();

                int randomItemID = config.getItem("RandomItem", 20000).getInt();

                // Since this flag is a boolean, we can read it into the variable directly from the config.
                someConfigFlag = config.get(Configuration.CATEGORY_GENERAL, "SomeConfigFlag", false).getBoolean(false);
               
                //Notice there is nothing that gets the value of this property so the expression results in a Property object.
                Property someProperty = config.get(Configuration.CATEGORY_GENERAL, "SomeConfigString", "nothing");
               
                // Here we add a comment to our new property.
                someProperty.comment = "This value can be read as a string!";
               
                String someConfigString = someProperty.value;
                // this could also be:
                // int someInt = someProperty.getInt();
                // boolean someBoolean = someProperty.getBoolean(true);

                config.save();
        }

        @Init
        public void load(FMLInitializationEvent event)
        {
                // now the blockID can be set in a configuration file
                randomBlock = (new RandomBlock(randomBlockID , 5))
                                .setHardness(1.5F)
                                .setResistance(10.0F)
                                .setStepSound(Block.soundStoneFootstep)
                                .setBlockName("Random Block");

                // where 20000 is the ItemID I want to assign it, and 2 is the texture.
                randomItem = (new RandomItem(randomItemID, 2));
        }
       
        @PostInit
        public void postInit(FMLPostInitializationEvent event) {
               
        }

        // These fields save the IDs between function calls
        public static int randomBlockID;
        public static int randomItemID;

        public static Block randomBlock;
        public static Item  randomItem;
        public static boolean someConfigFlag;
}

The Generated Configuration File

Here are the contents of the generated configuration file using the dummy mod.

# Configuration file
# Generated on 2/27/13 9:52 AM

####################
# block
####################

block {
    I:RandomBlock=4095
}


####################
# general
####################

general {
    B:SomeConfigFlag=false

    # This value can be read as a string!
    S:SomeConfigString=nothing
}


####################
# item
####################

item {
    I:RandomItem=20000
}


--AbrarSyed 08:11, 25 July 2012 (PDT)

--Updated by MysteriousAges for Forge 312+

Personal tools
Namespaces
Variants
Actions
Navigation
tutorials
Toolbox