Skip to main content

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

FunctionReturnsDescription
StartLoadMods()voidScans the Mods directory and loads all valid mods. Call once after binding delegates.
UnloadMod(ModId)boolUnmounts a specific mod by ID
UnloadAllMods()int32Unmounts all loaded mods (returns the count)
ReloadMod(ModId)boolHot-reloads a mod in-place (Editor only — use for iteration)

Querying

FunctionReturnsDescription
GetLoadedMods()TArray<FModDescriptor>All successfully loaded mods
IsModLoaded(ModId)boolCheck if a mod is loaded
IsModExist(ModId)boolCheck 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)boolCheck if a specific mod failed
GetFailedMod(ModId)FModLoadFailureFailure 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

FunctionReturnsDescription
SetModEnabled(ModId, bEnabled)boolEnable/disable a mod (persisted to disk; applied immediately if loading is complete). Refused during a multiplayer session.
IsModEnabled(ModId)boolCheck if a mod is enabled

Asset Queries

FunctionReturnsDescription
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():

DelegateSignatureFired 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:

FieldTypeDescription
ModIdFStringUnique identifier (e.g., "my_awesome_mod")
DisplayNameFStringHuman-readable name
VersionFStringSemVer string (e.g., "1.2.0")
AuthorFStringAuthor name
DescriptionFStringShort description
MinGameVersionFStringMinimum required game version
MaxGameVersionFStringMaximum supported game version (empty = no upper bound)
DependenciesTArray<FString>ModIds this mod requires
CppModuleNamesTArray<FString>Native modules declared by the mod — its presence causes the mod to be rejected
TagsTArray<FString>Categorization tags
ThumbnailPathFStringPath to thumbnail image in PAK
PackageSizeBytesint64PAK file size
ReleaseDateFStringISO 8601 UTC
UpdatedDateFStringISO 8601 UTC
bEnabledboolWhether this mod is enabled

EModLoadResult

Returned by OnModFailed to describe why a mod failed:

ValueDescription
SuccessLoaded successfully
PakNotFound.pak file missing or unreadable
InvalidDescriptorModDescriptor.json missing, malformed, or invalid
GameVersionTooOldGame version is lower than mod's MinGameVersion
GameVersionTooNewGame version is higher than mod's MaxGameVersion
MissingDependencyA required mod is not loaded
CircularDependencyDependency cycle detected in the dependency graph
DuplicateModIdAnother mod with the same ModId is already loaded
MountFailedPAK mount failed (file permissions, corruption, etc.)
ContainsNativeCodePAK contains .dll files (rejected for security)
InternalErrorUnexpected error during loading

Load Order

When StartLoadMods() is called:

  1. Scan — recursively finds all .pak files in the Mods directory
  2. Parse — reads ModDescriptor.json from each PAK
  3. Validate — checks game version compatibility, detects duplicates
  4. Sort — topological sort respecting Dependencies arrays
  5. Mount — mounts each PAK at priority 100 (overrides /Game/ content)
  6. Register — adds to FModRegistry
  7. Notify — fires OnModLoaded or OnModFailed for each mod
  8. Done — fires OnAllModsLoaded
PAK Priority

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.