Code Snippets/Classes

ratchet freak

Well-Known Member
Nov 11, 2012
1,198
243
79
This method lets you replace a final field:
Code:
public static final void replaceField(Class<?> c, String fieldName, Object replacement) {
        try {
            Field f = c.getDeclaredField(fieldName);
           
            Field m = Field.class.getDeclaredField("modifiers");
            m.setAccessible(true);
            m.setInt(f, f.getModifiers() & ~Modifier.FINAL);
           
            f.setAccessible(true);
            f.set(f, replacement);
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
    }

This gives you the current time:
Code:
SimpleDateFormat t = new SimpleDateFormat("HH:mm:ss");
String time = t.format(Calendar.getInstance().getTime());

H is hour, m is minutes, s is second, y is year, d is date and M is month.

Another example and a possible use for it (not really useful for modding though):
Code:
SimpleDateFormat year = new SimpleDateFormat("yyyy");
String copyright = "CoolSquid  " + year.format(Calendar.getInstance().getTime()) + ".";

it's faster to cache the Field object between calls and it may cause glitches when the field is statically initialized due to inlining

that time is the system time not the ingame time

copyright text should be static as it shows when the version was released
 

ljfa

New Member
Jul 29, 2019
2,761
-46
0
Since 1.7 config GUIs exist. It is possible to edit configurations ingame in a GUI without necessarily needing to restarting Minecraft.
For anyone who doesn't know where to find these: If you click on the "Mods" button on the main title screen you get a list of loaded mods. When clicking on a mod you will see a "Config" button on the bottom left if the mod supports config GUIs.

@Minalien has a tutorial on how to make your mod compatible with config GUIs. But she only covers the case of one single category. What if you want to use more than one category, displaying each category in a separate page?
You can do this by adapting your main ConfigGui class like this:
Code:
public class MyModConfigGui extends GuiConfig {
    public MyModConfigGui(GuiScreen parent) {
        super(parent, getConfigElements(), Reference.MODID, false, false, "My mod's configuration");
    }
  
    /** Compiles a list of config elements */
    private static List<IConfigElement> getConfigElements() {
        List<IConfigElement> list = new ArrayList<IConfigElement>();
      
        //Add categories to config GUI
        list.add(categoryElement(Config.CATEGORY_GENERAL, "General", "mymod.configgui.ctgy.general"));
        list.add(categoryElement(Config.CATEGORY_FOO, "Foo", "mymod.configgui.ctgy.foo"));
        list.add(categoryElement(Config.CATEGORY_BAR, "Bar", "mymod.configgui.ctgy.bar"));
      
        return list;
    }
  
    /** Creates a button linking to another screen where all options of the category are available */
    private static IConfigElement categoryElement(String category, String name, String tooltip_key) {
        return new DummyConfigElement.DummyCategoryElement(name, tooltip_key,
                new ConfigElement(Config.conf.getCategory(category)).getChildElements());
    }
}

Instead of displaying only the main category on the main screen, the call to getConfigElements() will instead make a list of buttons which lead to sub-screens, one sub-screen for each category.

The other part needed for the config GUI to work is the GUI factory, which Minalien also covers:
Code:
public class MyModGuiFactory implements IModGuiFactory {
    @Override
    public void initialize(Minecraft minecraftInstance) {}

    @Override
    public Class<? extends GuiScreen> mainConfigGuiClass() {
        return MyModConfigGui.class;
    }

    @Override
    public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
        return null;
    }

    @Override
    public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
        return null;
    }
}
To make your config GUI actually work you need to put the GUI factory's class name into the @Mod annotation like this:
Code:
@Mod([...], guiFactory = "fully.qualified.name.of.MyModGuiFactory")
which of course you can also put into a Reference class.
Refer to Minalien's tutorial for details.
 
Last edited:

ljfa

New Member
Jul 29, 2019
2,761
-46
0
I just noticed that config GUIs are already listed, but without much detail on how to use them (and without the stuff I added).
 

Minalien

New Member
Jul 29, 2019
40
0
0
@Minalien has a tutorial on how to make your mod compatible with config GUIs. But she only covers the case of one single category. What if you want to use more than one category, displaying each category in a separate page?

Just a note, the link has changed as I plan to repurpose my website. https://github.com/Minalien/BlogArchive/blob/master/ForgeTutorials/Spotlight__Config_GUIs.md :)

There were plans to expand it, but life kind of got in the way of a lot of things. It's definitely nice to see in-game config GUIs getting more attention, and I'd be happy to add a link to your snippet (which is probably much more up-to-date in general as well) to the archived tutorial as well. :)
 

ljfa

New Member
Jul 29, 2019
2,761
-46
0
Oh that's why the link is dead.
I changed the link in my post.

There were plans to expand it, but life kind of got in the way of a lot of things. It's definitely nice to see in-game config GUIs getting more attention, and I'd be happy to add a link to your snippet (which is probably much more up-to-date in general as well) to the archived tutorial as well. :)
Go ahead :)
 

ljfa

New Member
Jul 29, 2019
2,761
-46
0
Until then, I have two small functions for generating triangular distributed random numbers:
Code:
/** Generates a symmetrically triangular distributed integer between min and max (inclusive).
 * The expected value is (min+max)/2.
 */
public static int triangularInt(Random rand, int min, int max) {
    int span = max-min;
    return min + rand.nextInt(span/2 + 1) + rand.nextInt((span+1)/2 + 1);
}

/** Generates a symmetrically triangular distributed double in ]min, max[.
 * The modus and expected value is (min+max)/2.
 */
public static double triangularDouble(Random rand, double min, double max) {
    return min + 0.5*(max-min)*(rand.nextDouble() - rand.nextDouble() + 1.0);
}
Use these if you want numbers near the mean to appear more often.