Skip to main content

Quick Start — Game Dev SDK

This guide walks you through the minimum integration to get mods loading in your game.

Step 1 — Configure Your Mods Directory

By default, ModKit scans a folder named Mods alongside your game's Content directory. You can change this name in Project Settings → Plugins → ModKit Runtime → Mods Directory.

In a packaged game build, the Mods folder sits alongside Content/, inside the game's project folder:

MyGame.exe
MyGame/
├── Binaries/
├── Content/ ← game content (untouched)
├── Mods/ ← create this folder
│ └── MyMod/ ← one subfolder per mod
│ ├── MyMod.pak
│ ├── MyMod.ucas (IoStore — UE 5.4+ only)
│ ├── MyMod.utoc (IoStore — UE 5.4+ only)
│ ├── ModDescriptor.json
│ └── thumbnail.png (optional)
└── Saved/

Each mod is distributed as a folder. Players drop the entire mod folder into Mods/.

ModDescriptor.json Must Be Alongside the PAK

ModKit reads ModDescriptor.json from the same directory as the .pak before mounting it. A .pak without a descriptor is skipped.

Step 2 — Bind Delegates

Before calling StartLoadMods(), bind the delegates you care about on UModLoaderSubsystem. This ensures your game receives events as each mod loads.

Blueprint

Blueprint nodes for binding delegates

In your GameInstance Init event or Loading Screen Begin Play:

  1. Get the ModLoaderSubsystem node
  2. Bind OnModStartLoading, OnModLoaded, OnModLoadFailed, OnAllModsLoaded events
  3. Call StartLoadMods

C++

#include "ModLoaderSubsystem.h"

void UMyGameInstance::Init()
{
Super::Init();

UModLoaderSubsystem* ModLoader = GetSubsystem<UModLoaderSubsystem>();
if (ModLoader)
{
ModLoader->OnModStartLoading.AddUObject(this, &UMyGameInstance::OnModStartLoading);
ModLoader->OnModLoaded.AddUObject(this, &UMyGameInstance::OnModLoaded);
ModLoader->OnModLoadFailed.AddUObject(this, &UMyGameInstance::OnModLoadFailed);
ModLoader->OnAllModsLoaded.AddUObject(this, &UMyGameInstance::OnAllModsLoaded);
}
}

Step 3 — Call StartLoadMods

StartLoadMods() is never called automatically — you must call it explicitly at the right moment in your game flow.

Call Order Matters

Always bind your delegates before calling StartLoadMods(). If you call it first, you may miss OnModLoaded events for mods that load synchronously.

Recommended location: in your loading screen or main menu initialization, after your game world has fully initialized.

Blueprint

Event BeginPlay
→ Get ModLoaderSubsystem
→ Bind delegates (see above)
→ StartLoadMods

C++

void UMyLoadingScreen::NativeConstruct()
{
Super::NativeConstruct();

UModLoaderSubsystem* ModLoader = GetGameInstance()->GetSubsystem<UModLoaderSubsystem>();
if (ModLoader)
{
// Delegates already bound in GameInstance::Init
ModLoader->StartLoadMods();
}
}

Step 4 — Handle Events

OnAllModsLoaded

OnAllModsLoaded node

Called once after all mods have finished loading (or failed). Use this to proceed to your main menu or game world.

void UMyGameInstance::OnAllModsLoaded()
{
TArray<FModDescriptor> Mods = ModLoader->GetLoadedMods();
UE_LOG(LogTemp, Log, TEXT("Loaded %d mods"), Mods.Num());

// Proceed to main menu
GetWorld()->ServerTravel("/Game/Maps/MainMenu");
}

OnModLoaded

OnModLoaded node

Called for each successfully loaded mod. Useful for showing per-mod progress in a loading UI.

void UMyGameInstance::OnModLoaded(const FModDescriptor& Mod)
{
UE_LOG(LogTemp, Log, TEXT("Mod loaded: %s v%s by %s"),
*Mod.DisplayName, *Mod.Version, *Mod.Author);
}

OnModStartLoading

OnModStartLoading node

Called just before a mod begins mounting. Useful to show a "Loading: ModName..." message in a loading UI.

void UMyGameInstance::OnModStartLoading(const FString& ModId)
{
UE_LOG(LogTemp, Log, TEXT("Loading mod: %s"), *ModId);
}

OnModLoadFailed

OnModLoadFailed node

Called when a mod fails to load. The mod is skipped — your game continues.

void UMyGameInstance::OnModLoadFailed(const FString& ModId, const FString& Reason, EModLoadResult Result)
{
UE_LOG(LogModKitLoader, Warning, TEXT("Mod %s failed (%s): %s"),
*ModId, *UEnum::GetValueAsString(Result), *Reason);
}

Full Example Flow

Game Launch
└─ GameInstance::Init()
└─ ModLoaderSubsystem → StartLoadMods()

├─ Scans Mods/ for mod folders
├─ Validates each mod (descriptor, version, dependencies)
├─ Sorts by dependency order
└─ Mounts each PAK (priority 100 — shadows /Game/ content)

Loading Screen
└─ BeginPlay / NativeConstruct
├─ OnModStartLoading ───→ show progress
├─ OnModLoaded ─────────→ update loading UI
├─ OnModLoadFailed ─────→ log warning, skip mod

└─ OnAllModsLoaded ─────→ Main Menu

Querying Loaded Mods

After loading, use UModLoaderSubsystem to query mods at runtime:

UModLoaderSubsystem* ModLoader = GetGameInstance()->GetSubsystem<UModLoaderSubsystem>();

// Get all loaded mods
TArray<FModDescriptor> Mods = ModLoader->GetLoadedMods();

// Check if a specific mod is loaded
bool bHasMod = ModLoader->IsModLoaded("my_mod_id");

// Search mods by name/author
TArray<FModDescriptor> Results = ModLoader->SearchMods("my search query");

// Filter by tag
TArray<FModDescriptor> TaggedMods = ModLoader->GetModsByTag("gameplay");

Next Steps

Configuration — Full settings reference
Content Registry — Class overrides and DataTable merging
Security — Native-code rejection & version checks