Jump to content

Mod Loaders

From SA Docs

The Mod Loaders are Dynamic Link Libraries (DLL) files that inject themselves into the Sonic Adventure titles by replacing existing DLL files from the game. This is what allows mods to exist external to editing the existing files within the game as well as inject their own code into the game.

Below you'll find links to documentation pertaining to each mod loader respectively. These include in-depth looks at each one's specific APIs.

Mod Loader Export References

Below is an overview of the general exports that are available in the mod loaders. An example of a complete export can be seen below.

Variable Exports

ModInfo

ModInfo is a required export from any code based mod. Without it, the mod loader will not load the mod and will throw an error alerting the user that a mod is not a valid mod.

Example

// Example of exporting the ModInfo for SADX.
__declspec(dllexport) ModInfo SADXModInfo = { ModLoaderVer };

// Example of exporting the ModInfo for SA2B.
__declspec(dllexport) ModInfo SA2ModInfo = { ModLoaderVer };


Function Exports

The mod loaders support loading various function exports from a mod. While these are all optional, many mods make use of at least one of these exports as their entry point. This is most commonly the Init export.

Inside these exported functions you can put your own C++ code to manipulate data, replace assets or interface with the game.

Init

The Init (short for Initialize) export is used for initializing information within your mod and passing some variables from the mod loader into the mod itself. The include the mod's path (local path to the mod folder from the game's root), HelperFunctions (see each respective page for each mod loader for more information on this struct), and the mod's index in the list.

This is fired for all enabled mods first. It's fired in the order in which mods are loaded (top to bottom).

Example

__declspec(dllexport) void Init(const char* path, HelperFunctions& helperFunctions, const unsigned int index)
{
    
}


OnInitEnd

This is run after all mods have finished running their Init, but before the game has completely loaded. This is useful for any mods making APIs for other mods to utilize.

  This is only available in the SADX Mod Loader at this time.


Example

__declspec(dllexport) void OnInitEnd()
{
    
}


OnFrame

This export will run every frame. This can be useful if you need to check something within the game constantly. Users who utilize this should consider cautionary measures to prevent running large amounts of logic every frame if it can be avoided for performance reasons.

Example

__declspec(dllexport) void OnFrame()
{
    
}


OnInput

This export will run when the game processes input. More specifically, it will run just prior to the game actually processing that input.

Example

__declspec(dllexport) void OnInput()
{
    
}


OnControl

This export will run while the game is actively processing input.

Example

__declspec(dllexport) void OnControl()
{
    
}


OnRenderSceneStart

This export will run just before a game scene is rendered.

Example

__declspec(dllexport) void OnRenderSceneStart()
{
    
}


OnRenderSceneEnd

This export will run just after a game scene has finished rendering.

Example

__declspec(dllexport) void OnRenderSceneEnd()
{
    
}


OnRenderDeviceReset

This export will run whenever the render device for the game is reset. For example, resizing the game window will cause the render device to be reset.

Example

__declspec(dllexport) void OnRenderDeviceReset()
{
    
}


OnRenderDeviceLost

This export will run whenever a game scene fails to render.

Example

__declspec(dllexport) void OnRenderDeviceLost()
{
    
}


OnExit

This export runs just prior to the game completely closing.

Example

__declspec(dllexport) void OnExit()
{
    
}


Useful Functions and Macros

Inside any of the exported functions above, apart from your own custom C or C++ code, you can use the following functions and macros to replace game code and data in memory.

WriteData

WriteData writes the specified data at the specified memory address. You can use it to make small code patches, overwrite values, replace pointers etc.

Useful hacks:

  • Write 0xC3 to kill a function by writing a ret instruction.
  • Write 0x90 five times to kill a function call by writing five nop instructions.

Example

WriteData<1>((Uint8*)0x005ADC40, 0xC3); // Writes 0xC3 (one byte) to the address 0x005ADC40, effectively disabling the function located at that address.
WriteData<5>((Uint8*)0x0062EC3C, 0x90); // Writes 0x90 (five bytes) to the address 0x0062EC3C, effectively disabling the function call located at that address.
WriteData((Float*)0x00652F74, 800.0f); // Writes the floating point value of 800.0 to the address 0x00652F74.
WriteData((Float**)0x004D73FB, &MyFloat); // Replaces the pointer located at 0x004D73FB with the pointer to MyFloat.


WriteJump

WriteJump writes a jmp instruction at the specified memory address. You can use this to replace entire functions in the game with your own code.

Example

WriteJump((void*)0x005BBFE0, MyFunction); // Replaces the function at 0x005BBFE0 with a jump to MyFunction.

WriteJump(Function1, MyFunction); // Replaces the function Function1 (if defined with a FunctionPointer) with a jump to MyFunction.


WriteCall

WriteCall writes a call instruction at the specified memory address. You can use this to call your own code from the game's functions without replacing them entirely.

Example

WriteCall((void*)0x005AEF29, MyFunction); // Replaces the function call at 0x005AEF29 with a call to MyFunction.


Exportable Lists

The mod loaders also have support for exporting different types of lists. These are all optional exports.

Patch List

A PatchList is comprised of an array of PatchInfo entries. The mod loader will generate these using WriteData.

Example

// TODO: Insert example.


Jumps, Calls, and Pointer Lists

These three exportable lists are all comprised of an array of PointerInfo entries. On the mod loader's side, these arrays are handled like so:

  • Jumps are generated using WriteJump.
  • Calls are generated using WriteCall.
  • Pointers are generated using WriteData.

Example

// TODO: Insert examples.


Example

Example Export Table

// Inside of your mod's "main" cpp file (or whichever one houses your exports).
#include "pch.h"

HelperFunctions globalHelperFunctions;
const char* globalPath;

extern "C"
{
    __declspec(dllexport) SADXModInfo = { ModLoaderVer };


    __declspec(dllexport) Init(const char* path, HelperFunctions &helperFunctions, const unsigned int index)
    {
        // This passes the Mod Loader's HelperFunctions struct to your mod's.
        // This is necessary so the API related functions can work properly.
        globalHelperFunctions = helperFunctions;

        // This passes the mod's local folder path to the mod itself.
        // This is helpful for loading custom files.
        globalPath = path;
    }
}