Mod Loading System
UModLoaderSubsystem is the main entry point for everything mod-related at runtime. It is a GameInstance subsystem — one instance per game session, accessible from Blueprints and C++.
UModLoaderSubsystem Reference
Loading
| Function | Returns | Description |
|---|---|---|
StartLoadMods() | void | Scans the Mods directory and loads all valid mods. Call once after binding delegates. |
UnloadMod(ModId) | bool | Unmounts a specific mod by ID |
UnloadAllMods() | int32 | Unmounts all loaded mods (returns the count) |
ReloadMod(ModId) | bool | Hot-reloads a mod in-place (Editor only — use for iteration) |
Querying
| Function | Returns | Description |
|---|---|---|
GetLoadedMods() | TArray<FModDescriptor> | All successfully loaded mods |
IsModLoaded(ModId) | bool | Check if a mod is loaded |
IsModExist(ModId) | bool | Check if a mod was seen during the last scan (loaded, disabled, or failed) |
GetDisabledMods() | TArray<FModDescriptor> | Mods present in /Mods but with bEnabled=false |
GetFailedMods() | TArray<FModLoadFailure> | Failure records (ModId, Reason, Result, Descriptor) |
IsModFailed(ModId) | bool | Check if a specific mod failed |
GetFailedMod(ModId) | FModLoadFailure | Failure record for a specific mod |
SearchMods(Query) | TArray<FModDescriptor> | Case-insensitive search by DisplayName, Author, ModId |
GetModsByTag(Tag) | TArray<FModDescriptor> | Filter loaded mods by a single tag |
GetModsByTags(Tags) | TArray<FModDescriptor> | Filter loaded mods by multiple tags (OR — any match) |
GetAllTags() | TArray<FString> | The configured tag vocabulary (Project Settings), not per-mod tags |
Mod State
| Function | Returns | Description |
|---|---|---|
SetModEnabled(ModId, bEnabled) | bool | Enable/disable a mod (persisted to disk; applied immediately if loading is complete). Refused during a multiplayer session. |
IsModEnabled(ModId) | bool | Check if a mod is enabled |
Asset Queries
| Function | Returns | Description |
|---|---|---|
QueryModAssets(ModId, Query) | TArray<FAssetData> | Query a loaded mod's assets by class, name prefix, or substring |
LoadModThumbnail(ModId) | UTexture2D* | Load a mod's thumbnail as a texture (cached per session) |
Delegates
Bind these before calling StartLoadMods():
| Delegate | Signature | Fired When |
|---|---|---|
OnModStartLoading | (FString ModId) | A mod is about to start mounting |
OnModLoaded | (FModDescriptor) | A mod successfully mounted |
OnModLoadFailed | (FString ModId, FString Reason, EModLoadResult) | A mod failed to load |
OnAllModsLoaded | (int32 LoadedCount) | All mods in the scan have been processed |
FModDescriptor
The metadata struct describing a mod:
| Field | Type | Description |
|---|---|---|
ModId | FString | Unique identifier (e.g., "my_awesome_mod") |
DisplayName | FString | Human-readable name |
Version | FString | SemVer string (e.g., "1.2.0") |
Author | FString | Author name |
Description | FString | Short description |
MinGameVersion | FString | Minimum required game version |
MaxGameVersion | FString | Maximum supported game version (empty = no upper bound) |
Dependencies | TArray<FString> | ModIds this mod requires |
CppModuleNames | TArray<FString> | Native modules declared by the mod — its presence causes the mod to be rejected |
Tags | TArray<FString> | Categorization tags |
ThumbnailPath | FString | Path to thumbnail image in PAK |
PackageSizeBytes | int64 | PAK file size |
ReleaseDate | FString | ISO 8601 UTC |
UpdatedDate | FString | ISO 8601 UTC |
bEnabled | bool | Whether this mod is enabled |
EModLoadResult
Returned by OnModFailed to describe why a mod failed:
| Value | Description |
|---|---|
Success | Loaded successfully |
PakNotFound | .pak file missing or unreadable |
InvalidDescriptor | ModDescriptor.json missing, malformed, or invalid |
GameVersionTooOld | Game version is lower than mod's MinGameVersion |
GameVersionTooNew | Game version is higher than mod's MaxGameVersion |
MissingDependency | A required mod is not loaded |
CircularDependency | Dependency cycle detected in the dependency graph |
DuplicateModId | Another mod with the same ModId is already loaded |
MountFailed | PAK mount failed (file permissions, corruption, etc.) |
ContainsNativeCode | PAK contains .dll files (rejected for security) |
InternalError | Unexpected error during loading |
Load Order
When StartLoadMods() is called:
- Scan — recursively finds all
.pakfiles in the Mods directory - Parse — reads
ModDescriptor.jsonfrom each PAK - Validate — checks game version compatibility, detects duplicates
- Sort — topological sort respecting
Dependenciesarrays - Mount — mounts each PAK at priority 100 (overrides
/Game/content) - Register — adds to
FModRegistry - Notify — fires
OnModLoadedorOnModFailedfor each mod - Done — fires
OnAllModsLoaded
Mods are mounted at priority 100, higher than the base game (0). This means mod assets at the same path as game assets automatically shadow them — no additional code needed for asset overrides.
Mod Folder Layout
The Mods folder sits alongside Content/ in the game's project directory. ModKit scans one level deep inside it:
MyGame/
├── Content/
├── Mods/
│ ├── MyMod/
│ │ ├── MyMod.pak
│ │ ├── MyMod.ucas (IoStore — UE 5.4+)
│ │ ├── MyMod.utoc (IoStore — UE 5.4+)
│ │ ├── ModDescriptor.json ← required, read before mounting
│ │ └── thumbnail.png ← optional
│ └── AnotherMod/
│ ├── AnotherMod.pak
│ └── ModDescriptor.json
└── Saved/
Hot-Reload (Editor Only)
During development, use ReloadMod() to reload a mod without restarting the Editor:
UModLoaderSubsystem* ModLoader = GetGameInstance()->GetSubsystem<UModLoaderSubsystem>();
ModLoader->ReloadMod("my_mod_id");
This unmounts the old PAK, re-mounts the new one, and re-registers the mod. Useful when iterating on mod builds without restarting.