-
Notifications
You must be signed in to change notification settings - Fork 2
Mod Structure
A Quintessential mod is a folder or zip file, containing any number of textures and assets, possibly compiled code, and a quintessential.yaml file.
The quintessential.yaml file must be in the mod's root (i.e. directly inside the folder or zip file), and contains the mod's name and version, and optionally a list of dependencies, optional dependencies, and path to a DLL file. A simple example could be:
Name: MyMod
Version: 1.0.0The mod's name can be anything you like, but it's recommended to stick to alphanumeric characters. Spaces are stripped at runtime, and including those here may confuse you later on.
The mod's version should follow semantic versioning: major.minor.patch, where the patch number changes on bugfix releases, and the major version changes on releases that break existing saves, or break mods that depend on this.
A more complex file could look like this:
Name: TestMod
Version: 1.2.0
DLL: "TestMod/bin/Debug/net451/TestMod.dll"
Dependencies:
- Name: Quintessential
Version: 0.2.0
OptionalDependencies:
- Name: ZoomTool
Version: 0.1.0All dependencies must be present, at or above the specified version, for the mod to be loaded. The mod will always be loaded after dependencies.
If an optional dependency is present below the specified version, the mod won't be loaded. The mod will always be loaded after any present optional dependencies.
DLL is a relative path from the mod's root to a DLL file containing compiled code for the mod. Code modding is detailed later.
To include textures, create a Content folder in your mod's root. Any textures there will override vanilla's ones (if they have the same name and path). Other assets, like audio or text, can't be overridden yet.
To include code in your mod, create a "class library" project in Visual Studio (or equivalent for your IDE), targetting .NET Framework 4.5.1. Add the following assemblies from your Opus Magnum folder as assembly references:
ModdedLightning.exeMMHOOK_ModdedLightning.exeMono.Cecil.dllMonoMod.Utils.dllMonoMod.RuntimeDetour.dll
Note 1: MMHOOK_ModdedLightning.exe may not be present if Opus Mutatum failed to run MonoMod. Run OpusMutatum merge to generate it.
Note 2: Many IDEs copy these dependencies into the build folder, this is so they can be run immediately in a normal application based setting. However this isn't a normal development setup, and you have to move the mod.dll file to a mod folder inside the Opus Magnum/Mods folder, get into the habit of only moving the mod.dll file, or even better; write some code to do that for you.
Create a class that inherits from QuintessentialMod, and implement the abstract methods. You can use On and IL hooks to add to or modify vanilla code. See the RuntimeDetour README for more info.
Quintessential provides some utilities for adding parts, accessible in QApi. Adding atoms is also possible - see TestMod for an example. More utilities will be added to Quintessential in the future.
You can add settings to your mod, which can be accessed in the Mods menu and persist between loads. Create a class for storing your settings, with a public field per setting. Set the Settings field to an instance of your settings type, and override SettingsType to return the settings type.
Boolean fields appear as checkboxes, and SettingsButton fields appear as clickable buttons. To set the label for the field manually, assign the SettingsLabel attribute to the field. (Button fields, and anything else you don't want serialized, must be assigned YamlIgnore.)
Settings are loaded just before PostLoad, and ApplySettings is called whenever (non-button) settings are loaded or modified.
Example:
public class ModClass : QuintessentialMod {
public override void Load() {
Settings = new TestSettings();
}
// ...
public override Type SettingsType => typeof(MySettings);
public class MySettings {
[SettingsLabel("Look Henly, I'm a checkbox!")]
public bool MyCheckbox = false;
[YamlIgnore]
[SettingsLabel("Click me!")]
public SettingsButton Button = () => Logger.Log("I've been clicked!");
}
}When you make a class that inherits from QuintessentialMod, three methods must be defined (but can be empty).
- Load: Use the log function for a sanity check.
- PostLoad: Called after the game's initial loading.
- Unload: Call .Dispose() on any ILHooks.
Some other methods are also called automatically, but are optional.
- LoadPuzzleContent: Add all your atoms, glyphs, and other stuff.
- ApplySettings: Handle custom settings.
Here's an example of a simple mod:
using Quintessential;
namespace Foo;
public class Foo : QuintessentialMod
{
public override void Load()
{
Quintessential.Logger.Log("Hello, World!");
}
public override void PostLoad()
{
// Blank
}
public override void LoadPuzzleContent()
{
// Blank
}
public override void Unload()
{
// Blank
}
}Mods contained in .zip folders will automatically be unzipped before the game boots up, compressing the mod folder itself will likely not work, as the unzipped folder needs to have the quintessential.yaml file in the mod's root folder.
In File Explorer, navigate into your mods' folder, select the quintessential.yaml, dll file, Content directory, and any other vital file or folder. Right click and navigate to "Compress to > zip" to package up your mod, be sure to put it in an easily accessible location.
In the terminal, navigate into your mod's root directory, then run the zip (or tar) command to package the quintessential.yaml, dll file, Content directory (with its' subdirectories and files), and any other vital file or folder. Once finished, move your archive to an easily accessible location.