Skip to content

Core Architecture

Did you know?

The first mod for Persona 3 Portable on GameBanana appeared 40 minutes after the game released on PC?

No custom code, loader/launcher changes or archive repacking needed.
The user set dependency on Layer 1 mod; it just worked, like magic.

The architecture below is an extension of a tried and tested architecture from Reloaded-II. Now with custom backends!

Overall High Level View

How does it all look from a top-down view?

flowchart LR

    %% Define Stuff
    Bootloader["Bootloader"]
    Loader["Mod Loader"]

    subgraph "Mods"
        subgraph "Backends (Layer 0)"
        NET[".NET Backend"]
        end

        subgraph "Middleware/OS Handling Mods (Layer 1)"
        VFS["Virtual FileSystem"]
        CRICPK["CRI CPK Archive Support"]
        end

        subgraph "Game Support Mods (Layer 2)"
        GameSupport["Persona 5 Royal Support"]
        end

        subgraph "Regular Mods (Layer 3)"
        Character1["Joker Costume"]
        CodeMod["Cool .NET Code Mod"]
        end
    end

    %% Wire Things Up
    Bootloader --> Loader
    Loader -- Load 0th --> NET
    Loader -- Load 1st --> VFS
    Loader -- Load 2nd --> CRICPK
    Loader -- Load 3rd --> GameSupport
    Loader -- Load 4th --> Character1
    Loader -- Load 5th --> CodeMod

A typical setup for a certain recently released game might look something like this.

Bootloader

What is a Bootloader?

'Bootloader' in the spec refers to the component used to acquire arbitrary code execution inside the game's target process.

Basically, how we get our loader running.

Examples of some common approaches:

Mod Loader

What does the Mod Loader do?

The mod loader is responsible for figuring out which mods to load, loading them, and acting as a hub for messages being passed between mods.

Responsibilities of the loader include:

  • Locating the Profile for Current Game.
  • Loading the Actual Mods.
  • Logging: To File, Console etc.
  • Crash Handling & Error Reporting, e.g. Create a Minidump on Windows.
  • Working around DRM.

It is extremely important that the loader only ships the bare essentials, nothing else!

Mods

This is for illustration purposes only.

The 'Layers' presented below are only for the purposes of understanding how the overall system is composed; and how different mods rely on each other.

When the loader rearranges the load order based on dependencies, the overall order should become something similar to this.

To reiterate: There are no physical 'Layers' for mods in the Loader. This is just to help understanding.

Custom Backends (Layer 0)

Mods requiring a backend should transitively, or directly set a dependency on the backend.

Mods which are missing a direct or transitive dependency should be ignored, and the backend should instead log a warning to the console.

The Diagnostics system should warn users inside the launcher if it believes

The backend cannot have dependencies which rely on backend itself.

In other words, you must avoid circular dependencies.

The purpose of this layer is to add support for various runtimes if required by specific programming languages.

This layer can also be used for adding support for legacy mods from other loaders and/or legacy mods.

For more information see Backends.

Middleware/OS Handling Mods (Layer 1)

These mods add support for common middleware, APIs and/or hooking of operating system functions.

The Examples in this are:

Mod Description
Virtual FileSystem Allows the game to see and open files which aren't really there.
CRI CPK Archive Support Adds support for loading custom files in CRI Middleware .CPK.

The purpose of this layer is to provide the services and APIs necessary to make supporting new games easy.

These are reusable components you can use from the mods in the upper layers.

Note: The 'Classical' Approach

Traditionally each would write their own 'mod loader' from scratch to achieve these things; then copy the code for each subsequent project.

This has a few issues:

  • Improvement in one project doesn't carry over to others.
  • People may not be aware of other projects.
  • Everyone has to reinvent the wheel.

One of Reloaded3's main goals is to prevent this from happening.

Game Support (Layer 2)

These mods serve as an abstraction layer between regular mods and the lower level components

Mods in this layer have three main purposes:

  1. Provide simplicity for non-programmers.

    • This mod will set dependencies on multiple other mods such as the Virtual FileSystem or Archive Support.

    • Someone who's making a mod that replaces game files should only ever need to set a dependency on this mod.

  2. Provide resiliency to game updates.

    • Providing high level API/SDKs for game functionality that are guaranteed to not break between updates.

    • Providing function signatures and definitions (via headers) for APIs not covered by high level API/SDK.

  3. Providing interoperability between different mods:

    • Merging binary files (if needed) for various game file formats.

Important: For regular, non-technical modders; what matters is they just set a dependency on your game mod when creating their mod. This would be usually covered in a 'getting started' guide.

Regular Mods (Layer 3)

These are well, just regular mods.

They'll usually set a dependency on a layer 2 mod; and either just carry around game assets to replace in game folder; or their own custom code.

Lower Level Views

Shows how the overall system is composed using the sample of mods provided above.

From Perspective of Layer 0 (Backend) Mod

sequenceDiagram

    % Define Items
    participant Mod Loader
    participant .NET Backend
    participant Cool .NET Code Mod

    % Define Actions
    Mod Loader->>.NET Backend: Load Mod
    .NET Backend->>Mod Loader: Register Backend 'dotnet-latest'
    Mod Loader->>.NET Backend: Request to Load 'Cool .NET Code Mod' (via 'dotnet-latest')
    .NET Backend->>Cool .NET Code Mod: Load the Mod

The mod loader loads the mod. The backend mod uses a loader API to say 'hi, I can handle this backend'.

Down the road when the loader tries to load Cool .NET Code Mod, it sees it has backend dotnet-latest declared in its config and delegates loading to registered handler (.NET Backend).

From Perspective of Layer 2 (Game Support) Mod

sequenceDiagram

    % Define Items
    participant Mod Loader
    participant Virtual FileSystem (VFS)
    participant CRI CPK Archive Support
    participant Persona 5 Royal Support
    participant Joker Costume

    % Define Actions
    Mod Loader->>Persona 5 Royal Support: Load Mod
    Persona 5 Royal Support->>Mod Loader: Request CRI CPK Archive Support API
    Mod Loader->>Persona 5 Royal Support: Receive CRI CPK Archive Support Instance

    Mod Loader->>Joker Costume: Load Mod
    Mod Loader-->Persona 5 Royal Support: Notification: 'Loaded Joker Costume'
    Persona 5 Royal Support->>CRI CPK Archive Support: Add Files from 'Joker Costume' to CPK Archive (via API)

The Mod Loader loads the Persona 5 Royal Support Module as normal.

When down the road the loader loads the Joker Costume mod; an event 'ModLoaded' is fired.

The Persona 5 Royal Support mod picks up the notification, sees the mod included some folder to be added to the CPK Archive and calls the CRI CPK Archive Support API to map that folder.

The 'mod was loaded' callback is fired for every mod out there; to enable interactions of this kind.

Whole System

A top down overview of the overall loading procedure.

Note

This has been slightly simplified to exclude the lower level interactions necessary to load Backend based (Cool .NET Mod) and non-Code based (Joker Costume) mods shown above.

Look above to see how that's handled more closely.

sequenceDiagram

    % Define Items
    participant Mod Loader
    participant .NET Backend
    participant Virtual FileSystem (VFS)
    participant CRI CPK Archive Support
    participant Persona 5 Royal Support
    participant Cool .NET Code Mod
    participant Joker Costume

    % Define Actions
    Mod Loader->>.NET Backend: Load Mod
    .NET Backend->>Mod Loader: Register Backend

    Mod Loader->>Virtual FileSystem (VFS): Load Mod
    Virtual FileSystem (VFS)->>Mod Loader: Register API

    Mod Loader->>CRI CPK Archive Support: Load Mod
    CRI CPK Archive Support->>Mod Loader: Request VFS API
    Mod Loader->>CRI CPK Archive Support: Receive VFS Instance
    CRI CPK Archive Support->>Mod Loader: Register API

    Mod Loader->>Persona 5 Royal Support: Load Mod
    Persona 5 Royal Support->>Mod Loader: Request CRI CPK API
    Mod Loader->>Persona 5 Royal Support: Receive CRI CPK Instance

    Mod Loader->>Cool .NET Code Mod: Load Mod via .NET Backend Mod
    Mod Loader->>Joker Costume: Load Mod via Persona 5 Royal Support