Skip to content

How Centrifuge Works

Tomasz Cichoń edited this page Nov 9, 2019 · 7 revisions

Centrifuge relies on a few core components to get up and running before loading and initializing your mods. This document aims to explain what those components are and how they all work together to provide you with a working environment.

Spindle

Spindle is the assembly patcher for the entire Centrifuge project. It takes care of making the game assembly DLL aware of Centrifuge's existence in the first place by injecting a call to Centrifuge Bootstrapper into assemblies' module initializer. That entry point was chosen to provide the same well-known entry point in every Unity 5 game. As a bonus it helps ensure your code gets run after Unity initializes its own systems but before the actual game code is run. Spindle also supports injecting the call into any other library, including the Assembly-CSharp-firstpass or any Mono dependency assemblies the game might have.

Centrifuge

The Bootstrapper. It handles early system bring-up and relies on Unity Interop component which provides bridges. The bootstrapper is responsible for creating a console window when requested, creating a GameObject for mod loader to use as a starting point/frame update source and initializing the proxy component used by Reactor Manager to kickstart the mod loading process.

Centrifuge.UnityInterop

The Unity Interop component is the backbone of Centrifuge's game and Unity version agnosticism. It provides type bridges that resolve Unity types, methods, properties and fields at runtime using Reflection mechanism provided by .NET Framework. This component also creates Manager proxy type inheriting from MonoBehaviour. The type is generated at runtime in its entirety in order to free Centrifuge from hardlinking to any specific Unity assembly version. Helps avoid any copyright issues with Unity Technologies and game developers, too.

Reactor

Being the last component to actively run in the initialization sequence, Reactor sets up everything related to mods - Game Support Libraries (if any), provides Unity log interception, looks for any mod manifests and validates them, sorts mods according to load order deduced from priorities in the parsed manifests and then goes to initialize each mod which manifest successfully validated.

Mods are initialized according to the following action sequence:

▐ Check if an assembly with the declared file name exists.
▐ Load any dependency files declared in the manifest and located in mod dependency directory.
▐ Load the mod assembly.
▐ Validate the mod assembly:
    ◿ Check if it contains a single class decorated with the entry point attribute.
    ◿ Validate the Mod ID in the entry point attribute.
▐ Determine if we're dealing with MonoBehaviour entry point or a regular entry point.
▐ If dealing with MonoBehaviour entry point:
    ◿ Use Game Object Bridge to create a Unity Game Object.
    ◿ Call DontDestroyOnLoad on the created Game Object.
    ◿ Deactivate the Game Object if AwakeAfterInitialize was requested.
    ◿ Attach the entry point to the Game Object.
▐ If dealing with a regular class entry point:
    ◿ Create the entry point's instance using Activator.CreateInstance.
▐ Find initializer method configured using the entry point attribute and call it.
▐ If we're dealing with MonoBehaviour and it was deactivated on creation, reactivate it.

Reactor.API

This passive component provides a common set of tools for Game Support Libraries and Mods alike, so you can focus on what's important, rather than write boilerplate or "core" libraries and possibly give up before even getting started on modding your game. This is also what you'll get by default by downloading the Centrifuge.Mod.SDK NuGet package.

The toolset consists of:
▐ Reactor Settings System
▐ Common Logging System
▐ Virtual File System
▐ Messenger System
▐ Asset Loading System
▐ Game-independent Hotkey Management & Basic Input Processing
▐ Various .NET Framework extensions