Create mod config - X-Hax/SA2BModdingGuide GitHub Wiki

Both the SADX and SA2 Mod Loaders support Mod Configuration which can be set up by making a XML file (ConfigSchema.xml) that the Manager will read and create a custom Configuration menu for a mod.

The SAModManager, as of version 1.2.9, now supports codeless config creation. This is not supported by the legacy Mod Managers.

In this guide, we will go over how to create a Codeless Configuration and a Coded Configuration. These tutorials do assume you already have a mod created and some basic understanding on how a mod is created.


Codeless Configuration

For this example, we will implement two different options with multiple choices in one mod:

  • An option to swap one of the Super Sonic music from the Super Sonic Mod
  • A simple option to enable or disable a Tails Skin.

First of all, you need to open the SAModManager, select your mod, right click -> Edit Mod.

Once the edit window shows up, scroll down to the field Include Directories. This is what we want to edit. If you don't see it, make sure your Mod Manager is version 1.2.9 or higher. The Mod Config uses comma (,) separated strings to set the default directories that will be used for EACH of the different options. Please note that you can have spaces to help distinguish the options when writing them. These will automatically be trimmed when saving.

image

In this example here, the SuperstarsMusic folder will be the default option for the Super Sonic music replacement while Cream will be the default option for the Tails Skin replacement.

Please note that "default directory" refers to the default subfolder found in the mod for that specific option. You do not need to include all of the subfolders being used for different options.

Once you press OK, head over to your Mod's folder, and you should see the new folders that you listed in the Include Directories.

image

These subfolders will act like a standard mod directory (without a mod.ini file) for file replacement. This means that you can create your gd_pc, replacetex, etc folders within each directory as necessary. The way this works is that the Mod Manager will take the supplied Include Directories and load files found within them just like it would for a normal mod.

Now, in this example, let's say you want to have more choices for the Super Sonic music. You would need to create additional subfolders for any options you wanted to include. If you don't intend on having multiple options and are only wanting a simple Enable / Disable setup, then you can simply use one folder per option.

Once this has been set up, you can put any mod related files into their respective folders.

Super Sonic music replacement (Example):

image

Tails skin replacement (Example):

image

With the mod files setup, the last step is creating the ConfigSchema (XML) file that will be used by the Manager the mod's configuration.

Creating a Configuration Schema (XML) File

In the root of your mod's folder (were mod.ini is), create a new file called configschema.xml. You can use the following base to create your configuration schema:

<?xml version="1.0"?>
<ConfigSchema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.sonicretro.org">
	<Groups>
		<Group name="Gameplay" display="1. Gameplay">
			<Property name="IncludeDir0" display="Music Style" type="Music" defaultvalue="SuperstarsMusic">
				<HelpText>Select Current Music.</HelpText>
			</Property>	
			
			<Property name="IncludeDir1" display="Tails Skin" type="skin" defaultvalue="1">
				<HelpText>Select Tails Skin.</HelpText>
			</Property>	
	</Group>
</Groups>
		
	<Enums>
      <Enum name="Music">
			<EnumMember name="None" />
			<EnumMember name="SuperstarsMusic" />
		</Enum>
		
		 <Enum name="skin">
			<EnumMember name="0" display="Regular (sa2b)" />
			<EnumMember name="1" display="Cream" />
		</Enum>		
	</Enums>
</ConfigSchema>

This xml file will make the config option in the Mod Manager like this:

image

Let's break all of these down:

Property Groups

These groups hold different properties for configuration, most commonly they are bool properties, but they can also be int, string, enum, and float. Only bool and enum will be covered in this section.

  • Groups is the main array needed for storing property groups. These do not have additional groups.
  • Group is a grouping of properties. You can have several of these within a Groups array.
    • name is what will be saved to the config.ini file as the Group Header. You can use any name here.
    • display can be used to create a display name that is different to your name. It is not required.
  • Property is where you actually define a configuration item.
    • name is the name of the property. These are reserved under IncludeDirX (where X is a number) for codeless configurations. X refers to the index of your folder in the Include Directories list. These start at 0, so the first folder in your Include Directories would be IncludeDir0.
    • display is what is displayed in the Configuration menu for the property. If one is not set, this will default to the name. It's highly recommended to set a display value.
    • type is what the property actually is. In the example, both are set to enum types.
    • defaultvalue is what the default option should be. In most cases, this would be the first listing in an enum.
    • HelpText is an element nested within a Property. These are essentially descriptions of what the property does.

Enum Groups

  • Enums is the main array where any Enum elements are stored.
  • Enum is the group where you can create an enum. In the example, Music and skin are called by their name in the respective Properties that utilize them.
    • name is how the enum is referenced by a Property.
  • EnumMembers
    • name is what is actually written to the config.ini file. These MUST match any subfolder names you create.
    • display will be what is displayed in the dropdown box for enum selection in the property over the name property if it's set. These are great for making things read better to the user.

With all of this in mind, you should be ready to make your own configuration for your own mod. You can always work from the example as a base, and play around with the values to get a better understanding of how it all works.

NOTE: If the Mod Manager happens to crash when you click the Configure button with your mod selected, that means your ConfigSchema.xml file is incorrectly formatted. This is a common mistake. Be sure to pay attention to the syntax used, namely when to use "" and <>.

Even with these options, you can still have a gd_pc, or replacetex folder (or any other supported folders or data files) in the root of your mod's folder like any standard mod. This effectively allows you to have universal files that are loaded no matter what options the user has selected. This has the added benefit of reducing duplicated files and will help keep your mod's filesize down.

One final note: while testing your mod configuration, you will notice that a config.ini file is created when saving your configuration. You do not want to ship this file when releasing your mod, or in any updates. This can cause issues for users looking to play with your mod where they may have settings they don't want enabled just by downloading it, or their configuration may accidentally be overwritten due to an update.

Hopefully you have enough information from this guide to make basic options without needing to learn how to create a DLL mod.

Troubleshooting your Mod Config

If your options don't work in game, please check the following steps:

  1. Make sure each of your Property name uses IncludeDirX, this is mandatory for your config to work.

config

  1. Check if mod.ini is referencing your current enabled options (It should always do it automatically when you swap Config in the Manager.)

ModIniWrong

  1. Make sure each of your Enum Member name matches your subfolder name.

3

Feel free to join the X-Hax Discord Server if you need any help!


Coded Configuration

If you want more possibilities than just basic file replacement, it is possible to use custom code with a DLL mod to implement basically anything depending on the current option.

The configschema file has a lot more features that can be combined with a DLL mod, we used enum for basic replacement, but if you use code you can use string, float, int, bool etc.

Additionally, more elements that you can implement in your XML file:

  • minvalue: the minimum value for integer/float property values.
  • maxvalue: the maximum value for integer/float property values.
  • alwaysinclude: whether the property should be written in the ini if it's using the default value.

First, you will have to set up a DLL Mod if you haven't already.

Once it's done you will need to make your code read the ini file that the Mod Loader will yield, you can use the IniFile class that MainMemory wrote in mod-manager-common.

Importing the class

Easy method:

  1. Copy IniFile.hpp, IniFile.cpp, Utils.hpp, TextConv.hpp and TextConv.cpp in your project folder.
  2. Move the two cpp files next to your other source files in Visual Studio.
  3. If you have pch.h instead of stdafx.h, rename the stdafx.h includes in IniFile.cpp and TextConv.cpp to pch.h.
  4. Remove security warnings (or resolve them.)

Git method:

  1. Add the mod-manager-common repository as a submodule.
  2. In Visual Studio, right click your solution, click "add existing project", and add ModLoaderCommon.vcxproj.
  3. Then right click your project, click on build order, and make "mod-loader-common" as a dependency of your project.
  4. Open the properties of your project, go to additional includes and add $(SolutionDir)mod-loader-common/ModLoaderCommon.
  5. In the Linker -> Input -> Additional Dependencies, add $(SolutionDir)bin\ModLoaderCommon.lib.

It should now build. Note that you can add sa2-mod-loader as a submodule instead, as mod-loader-common is already part of it.

The code

Head over to the cpp file with the Init function and add #include "IniFile.hpp" below the pch/stdafx include.

Then you can adapt the following code to your need in the Init function:

const IniFile* config = new IniFile(std::string(path) + "\\config.ini");

bool value_bool = config->getBool("", "ConfigBool", true);
int value_int = config->getInt("", "ConfigInt", 120);
float value_float = config->getFloat("", "ConfigFloat", 1.25f);
std::string value_string = config->getString("", ConfigCharacter, "Sonic");

delete config;

Any of the get function work as follows: it first take the group name (we only use an empty named group), then the parameter name and finally the default value that will be used if config.ini is missing or if the setting is missing from it.

That's it!

⚠️ **GitHub.com Fallback** ⚠️