Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4c8e61c
Implement C++ Mod Config.
Sora-yx Sep 15, 2026
8bbcc06
Fix typo in the doc (ended dropping crossplatform)
Sora-yx Sep 15, 2026
7fb4acf
ModConfig: Fix missing 32 bits mod template reference.
Sora-yx Sep 15, 2026
00d437e
Syntax moment
Sora-yx Sep 15, 2026
a1658e0
Handle null case for when user config directory is null (+ rework mig…
Sora-yx Sep 16, 2026
a423fff
Validate filename helper + add missing "Values" for enum
Sora-yx Sep 16, 2026
e924738
Inlined enum stuff through helper functions
Sora-yx Sep 16, 2026
7308d68
Invoke and Migrate improvement stuff.
Sora-yx Sep 16, 2026
9671e70
Reloaded Mod Config header: Add mutex for thread safe + API struct
Sora-yx Sep 16, 2026
8db149d
Documentation fixes: formatting adjust + rework CMake to use env vari…
Sora-yx Sep 16, 2026
ef58379
wrapper to the loader API
Sora-yx Sep 18, 2026
3b0573e
Changed: Improve/shorten NativeMods docs
Sewer56 Sep 20, 2026
da26497
Changed: Shorten native mod template README
Sewer56 Sep 20, 2026
9055250
Changed: Remove unused usings from native config tests
Sewer56 Sep 20, 2026
98c866e
Changed: Polish native config docs and clear new-code warnings
Sewer56 Sep 20, 2026
756a7a8
Changed: Group native mod config types under Native subnamespace
Sewer56 Sep 20, 2026
1f8bd02
Changed: Split native mod config schema models into Schema subnamespace
Sewer56 Sep 20, 2026
405b14c
Changed: Link native schema docs to C# interface types
Sewer56 Sep 20, 2026
14c1c83
Update: Doc cleanup of ConfigurableBase.cs
Sewer56 Sep 20, 2026
1dfb6cb
Style: ModConfigSchema added newline
Sewer56 Sep 20, 2026
a15949f
Style: Fix initializer alignment in picker schema parsers
Sewer56 Sep 20, 2026
eadcbad
Fixed: Remove duplicate blank line in ConfigureModCommand
Sewer56 Sep 20, 2026
7b9e43e
Changed: Link plain doc mentions to code members
Sewer56 Sep 20, 2026
0fa2850
Changed: Dedupe native and managed configurator setup
Sewer56 Sep 20, 2026
e799103
Changed: Add Arrange/Act/Assert sections to native mod tests
Sewer56 Sep 20, 2026
cc6ff21
Changed: Removed redundant comment
Sewer56 Sep 20, 2026
0aa172d
Native Mod Config: swap to Enum + add missing json exception + valida…
Sora-yx Sep 21, 2026
86c1e4d
Updated documentation to add enum property and InitialFolderPath
Sora-yx Sep 21, 2026
fa6bbc2
Rewrite logger to be more like C# equivalent
Sora-yx Sep 22, 2026
adcc59a
Changed: Remove docs for wrapper funcs
Sewer56 Sep 22, 2026
1a9c095
Changed: Use nint instead of IntPtr in native mod config code
Sewer56 Sep 22, 2026
5a04cc4
Removed: Redundant external-write retry comment in ConfigurableBase
Sewer56 Sep 22, 2026
9e877f6
Changed: Use Environment alias for System.Environment in native schema
Sewer56 Sep 22, 2026
f67f40a
Changed: Clarify native mod documentation
Sewer56 Sep 22, 2026
e0b8550
Changed: Show config and logging usage in C++ example
Sewer56 Sep 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion docs/NativeMods.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,105 @@ You can control which file the mod loader will load for x64 and x86 processes us
```
To generate the config file, create a new mod from within the launcher.

## User Settings (Config Dialog)

Native mods can expose settings in the launcher's *Configure* dialog without any C# code, through a declarative schema file. Place a `ConfigSchema.json` file next to your `ModConfig.json` describing your settings, and the launcher builds the same configuration UI used by C# mods: checkboxes, numeric boxes, sliders, dropdowns, file and folder pickers, with categories, tooltips and a Reset button.
Comment thread
Sewer56 marked this conversation as resolved.
Outdated

A minimal schema looks like this:

```json
{
"Configurations": [
{
"FileName": "Config.json",
"DisplayName": "Default Config",
"Enums": [
{
"Name": "Quality",
"Members": [ { "Name": "Low" }, { "Name": "High", "DisplayName": "High Quality" } ]
}
],
"Properties": [
{
"Name": "EnableThing",
"Type": "bool",
"DisplayName": "Enable Thing",
"Description": "Turns the thing on or off.",
"Category": "General",
"Order": 0,
"DefaultValue": true
},
{
"Name": "Volume",
"Type": "int",
"DefaultValue": 75,
"Slider": { "Minimum": 0.0, "Maximum": 100.0, "SmallChange": 1.0, "LargeChange": 10.0, "TickFrequency": 10, "ShowTextField": true }
},
{ "Name": "Brightness", "Type": "float", "DefaultValue": 1.5 },
{ "Name": "Quality", "Type": "Quality", "DefaultValue": "High" },
{ "Name": "CustomFile", "Type": "string", "FilePicker": { "Title": "Choose a File" } }
]
}
]
}
```

Notes:

- `Type` is one of `bool`, `int`, `float`, `double`, `string`, or the name of an entry in `Enums`.
- `DisplayName`, `Description`, `Category`, `Order` and `DefaultValue` mirror the attributes used by the C# mod template.
- `Slider`, `FilePicker` and `FolderPicker` mirror the `SliderControlParams`, `FilePickerParams` and `FolderPickerParams` attributes; all fields are optional.
- Each entry in `Configurations` becomes one page of the dialog, saved to its own file (`FileName`) inside the mod's user config folder (`User/Mods/<ModId>`). Values missing from the file fall back to `DefaultValue`.

The values are saved as a flat JSON file such as:

```json
{
"EnableThing": false,
"Volume": 10,
"Brightness": 0.25,
"Quality": "Low"
}
```

### Reading the Settings from C/C++
Comment thread
Sewer56 marked this conversation as resolved.
Outdated

To read the settings inside your mod, copy `ReloadedModConfig.h` (from the [native mod template](https://github.com/Reloaded-Project/Reloaded-II/tree/master/source/Reloaded.Mod.Template/templates/native)) into your project and define `RELOADED_MOD_CONFIG_IMPL(your_start_function)` in exactly one source file. The macro exports `ReloadedStartEx`, which the loader calls with your mod's folders:

```cpp
#include "ReloadedModConfig.h"

static void my_start()
{
auto& config = reloaded::config();
bool enabled = config.get_bool("EnableThing", true);
long long volume = config.get_int("Volume", 75);
double brightness = config.get_float("Brightness", 1.5);
std::wstring file = config.get_wstring("CustomFile", L"");

static const char* quality[] = { "Low", "High" };
int qualityIndex = config.get_enum("Quality", quality, 2, 1);
}

RELOADED_MOD_CONFIG_IMPL(my_start)
```

Missing values fall back to the schema defaults, then to the fallback argument. The header only needs the C++17 standard library (or later) and only work on Windows.

## Exports

**Entry Points:**

Reloaded tries to start mods by using the following entry points in order:

- ReloadedStartEx
- ReloadedStart
- InitializeASI
- Init

If none of these entry points is found, the mod will not be loaded.
The exported methods should have no parameters and return `void`.

`ReloadedStartEx` is defined as `void fn(const wchar_t* modDirectory, const wchar_t* userConfigDirectory)` and receives the mod's own folder (where `ConfigSchema.json` lives) and the folder where the launcher stores user settings. Use it (or the helper header above) if your mod reads its configuration. The other entry points should have no parameters and return `void`.
Comment thread
Sewer56 marked this conversation as resolved.
Outdated

**Suspend, Resume, Unload:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,40 @@ private bool TryGetConfiguratorDisposing()
private bool TryGetConfigurator(out IConfiguratorV1? configurator, out PluginLoader? loader)
{
var config = _modTuple!.Config;
string dllPath = config.GetManagedDllPath(_modTuple.Path);
configurator = null;
loader = null;

var modDirectory = Path.GetFullPath(Path.GetDirectoryName(_modTuple.Path)!);

// Native (C/C++) mods describe their settings in a schema file, no managed code required.
Comment thread
Sora-yx marked this conversation as resolved.
Outdated
if (NativeModConfigSchema.ExistsInFolder(modDirectory))
{
// Validate upfront, a broken schema disables the button instead of failing later.
NativeModConfigSchema.Load(modDirectory);

var nativeConfigurator = new NativeModConfigurator(modDirectory);
nativeConfigurator.SetModDirectory(modDirectory);

if (_modUserConfigTuple != null)
{
var configDirectory = Path.GetFullPath(Path.GetDirectoryName(_modUserConfigTuple.Path)!);
nativeConfigurator.Migrate(modDirectory, configDirectory);
nativeConfigurator.SetConfigDirectory(configDirectory);
}
Comment thread
Sora-yx marked this conversation as resolved.
Outdated

nativeConfigurator.SetContext(new ConfiguratorContext()
{
Application = _applicationTuple.Config,
ModConfigPath = _modTuple.Path,
ApplicationConfigPath = _applicationTuple.Path
});

configurator = nativeConfigurator;
return true;
}

string dllPath = config.GetManagedDllPath(_modTuple.Path);

if (!File.Exists(dllPath))
return false;

Expand All @@ -89,7 +119,6 @@ private bool TryGetConfigurator(out IConfiguratorV1? configurator, out PluginLoa
return false;

configurator = (IConfiguratorV1)Activator.CreateInstance(entryPoint)!;
var modDirectory = Path.GetFullPath(Path.GetDirectoryName(_modTuple.Path)!);
configurator.SetModDirectory(modDirectory);

if (configurator is IConfiguratorV2 versionTwo && _modUserConfigTuple != null)
Expand Down
Loading