Jump to content

Forge config gui


fuzzybat23

Recommended Posts

I don't suppose anyone knows of any good tutorials on how to build a config gui in Forge?  You know, when you go into the main menu, click on mods, scroll down to yours and click on Config button.  One that's preferably in english?  It'd be nice if Forge put out a template for those.

  • Like 1
Link to comment
Share on other sites

If you use the annotation-based config system, a config GUI will automatically be created for your mod. All you need to do is subscribe to ConfigChangedEvent.OnConfigChangedEvent, check if the event's mod ID is your mod ID and then call ConfigManager.sync to synchronise the changes made to the Configuration object (by the GUI) back to the fields of your @Config class.

 

You can see an example of this here.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

14 minutes ago, fuzzybat23 said:

You don't know how to setup multiple pages in the Config screen, do you?

 

Each category will be given its own page.

 

Any field of the @Config class whose type is a class that directly extends Object will become a config category, with its fields becoming properties or categories following the same rules as the top-level class. Map fields are also mapped to categories with properties as key-value pairs.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

9 minutes ago, fuzzybat23 said:

Let me see if my sleep addled brain got that right.  Each time you declared a new public class in your example, that opened up a new category page?

 

The classes could be declared anywhere, it's the fields that use those classes that are mapped to categories.

  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

26 minutes ago, fuzzybat23 said:

I don't think I quite understand.  I'm still learning this stuff, so I'm not up to snuff on all the terms xD  What exactly do you mean by the fields the classes are mapped to?

 

Each field in the @Config class is mapped to either a configuration category or a configuration property depending on its type.

 

If it's a type that implements Map, a category is created and a property is created in that category for each key-value pair in the Map. The Map must have String keys and primitive, primitive array, String or enum values.

 

If it's a type that directly extends Object, a category is created and a sub-category or property is created in that category for each field of the class following the same rules as the @Config class. These classes can be declared anywhere, they don't have be nested in the @Config class.

 

If it's a primitive, primitive array, enum or String, a property is created.

 

If it's any other type, an error is thrown.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

Which file in your Git did you initially create and populate the configuration file that your ModConfig.java syncs to?  I'd like to compare it to mine.  I think I'm slowly getting a grasp on the usage of @Config  I'm also wondering how in your main class you initially access your ModConfig to open the Config screen.  None of the examples I've seen so far were using @Config, so the structure is quite a bit different.  Like..  This one for example, is some code I'm trying to convert to make use of @Config.

 

 

Edited by fuzzybat23
Link to comment
Share on other sites

package com.mmyzd.llor;

import java.io.File;
import java.util.ArrayList;

import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

public class ConfigManager {
	
	public Configuration file;
	
	public Property useSkyLight;
	public Property displayMode;
	public Property chunkRadius;
	public Property pollingInterval;
	public ArrayList<String> displayModeName = new ArrayList<String>();
	public ArrayList<String> displayModeDesc = new ArrayList<String>();
	
	public ConfigManager(File configDir) {
		file = new Configuration(new File(configDir, "LLOverlayReloaded.cfg"));
		displayModeName.add("Standard");
		displayModeName.add("Advanced");
		displayModeName.add("Minimal");
		displayModeDesc.add("Show green (safe) and red (spawnable) areas.");
		displayModeDesc.add("Show green (safe), red (always spawnable) and yellow (currently safe, but will be spawnable at night) areas.");
		displayModeDesc.add("Do not show green area. For other areas, use standard mode when not counting sky light, or advanced mode otherwise.");
		reload();
	}
	
	@SubscribeEvent
	public void onConfigurationChanged(ConfigChangedEvent.OnConfigChangedEvent event) {
		if (event.getModID().equals(LightLevelOverlayReloaded.MODID)) update();
	}
	
	void reload() {
		file.load();
		String comment = "How to display numbers? (default: 0)";
		for (int i = 0; i < displayModeName.size(); i++) {
			comment += "\n" + String.valueOf(i) + " - ";
			comment += displayModeName.get(i) + ": ";
			comment += displayModeDesc.get(i);
		}
		useSkyLight = file.get("general", "useSkyLight", false, "If set to true, the sunlight/moonlight will be counted in light level. (default: false)"); 
		displayMode = file.get("general", "displayMode", 0, comment);
		chunkRadius = file.get("general", "chunkRadius", 3, "The distance (in chunks) of rendering radius. (default: 3)");
		pollingInterval = file.get("general", "pollingInterval", 200, "The update interval (in milliseconds) of light level. Farther chunks update less frequently. (default: 200)");
		update();
	}
	
	public void update() {
		useSkyLight.set(useSkyLight.getBoolean(false));
		displayMode.set(Math.min(Math.max(displayMode.getInt(0), 0), displayModeName.size() - 1));
		chunkRadius.set(Math.min(Math.max(chunkRadius.getInt(3), 1), 9));
		pollingInterval.set(Math.min(Math.max(pollingInterval.getInt(200), 10), 60000));
		file.save();
	}
	
}

 

Link to comment
Share on other sites

9 minutes ago, Jay Avery said:

Is this the case in 1.11, or is it only in 1.12+?

It is true for 1.11 aswell.

 

4 minutes ago, fuzzybat23 said:

I'm working with 1.12.  I guess 1.12 doesn't utilize GuiFActory at all anymore, just the @Config?

You can still use both. The annotation based config system is just less messy and easier to use in general.

Link to comment
Share on other sites

14 minutes ago, V0idWa1k3r said:

It is true for 1.11 aswell.

Okay, in that case I'm confused. I've made a simple @Config class, it correctly reads the config file, but the "config" button in the mods list is still greyed out. Does the @Config class need to be registered or anything? 

Link to comment
Share on other sites

12 minutes ago, fuzzybat23 said:

So this created the gui for you.  How did you create your config file or did this automatically do that, too.

Yes it did. I have no idea why it isn't working for Jay and I know that forge indeed automatically creates both the gui and the file for annotation based configs without you explicitly telling it to do so from multiple tests.

 

14 minutes ago, fuzzybat23 said:

And if so, where does it get the default values for the file?

It takes the values from the fields at the moment of file creation.

Link to comment
Share on other sites

So when you did:

        @Config.Comment("Minimum Y coordinate for this ore")
		public int minHeight;

It created an entry in the config file with minHeight but with no value set, where if you did:

        @Config.Comment("Minimum Y coordinate for this ore")
public int minHeight = 20;

then it would have created the config file with minHeight = 20?

Link to comment
Share on other sites

No, those fields are not static and they can't be assigned to a property as there is no object that hosts them.

When I did this:

public final GenSettings oreAether = new GenSettings(1, 80, 128, 4,-1, 1);

It created a oreaether entry in the config file, and inside that entry it created multiple other entries with their values set according to the arguments i've passed. And this entry was created under a worldgen entry as this specified it:

public static final Generation worldGen = new Generation();

So in the end for that code the config file looks like this:

Spoiler

 

# Configuration file

general {

    worldgen {
    
        oreaether {
            # The list of dimension IDs this ore is NOT allowed to generate in
            I:blacklistDimensions <
                -1
                1
             >

            # Maximum Y coordinate for this ore
            I:maxHeight=128

            # Minimum Y coordinate for this ore
            I:minHeight=80

            # The amount of times the ore will try to generate in each chunk. Set to less than 1 to turn this into a chance to generate type of value
            D:triesPerChunk=1.0

            # The maximum size of the vein
            I:veinSize=4
        }

    }

}

 

 

Link to comment
Share on other sites

Ahhhh, I think I see.  Int... blacklistDimensions ended up with -1, and 1 because they were the only two left and blacklistDimensions is an array, right?  I  wonder, though, why those values were placed in the order they were in your config file then xD  I'd think that triesPerChunk would be at the top of the list, instead blacklistDimensions is.  I'd say that it entered them in reverse order from how they're declared in your code, except that veinSize ends up being the last one entered into the config file.

Edited by fuzzybat23
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.