Code Mod Setup - EverestAPI/Resources GitHub Wiki

Table of Contents

Project setup

Prerequisites

Celeste is written in C# and runs on .NET Framework 4.5.2. Modern Everest versions convert Celeste to run on .NET 7.0, the modern successor to .NET Framework. This means every Everest code mod starts out as a C# class library targeting .NET 7.0 (Core mods) or .NET Framework 4.5.2 (Legacy mods). Core mods provide access to all modern C# features as well as a lot of other advantages, but are only supported by .NET Core Everest builds - this means that such mods are incompatible with Everest versions below 4465.

Important

Everest uses semantic versioning 🔗.
This means that version numbers follow the format of MAJOR.MINOR.PATCH, and that changing the major version WILL break mods depending on your code mod.

So, if a mod depends on YourMod 1.3.5:

  • installing YourMod 1.0.x won't work
  • installing YourMod 1.3.0 won't work
  • installing YourMod 1.3.5 will work (of course)
  • installing YourMod 1.6.x will work
  • installing YourMod 2.0.x won't work. The user will have to get YourMod 1.3.x or above instead.

The simplest way to set up a code mod is using the CelesteMod.Templates dotnet template 🔗.

Windows

First, you need to open your Mods folder in Windows Terminal. You can do that by i.e. opening Olympus, clicking on Manage under Installations, and then clicking on Browse. A File Explorer window should show up.

Right click the Mods folder and click Open in Terminal.

Open in Terminal window

Note

If you don't have the Open In Terminal option, Shift+Right click the Mods folder and Open PowerShell window here instead.

If you have never made a code mod before, you need to install the template. Enter the below into Terminal and press Enter.

dotnet new install CelesteMod.Templates

Tip

Remember to run dotnet new update every now and then, to make sure your code mod template is up to date.

Then, to actually use the template, enter the following commands.
Remember to replace MyCelesteMod with your mod name.

md MyCelesteMod
cd MyCelesteMod
dotnet new celestemod

You should get an output similar to this:

Command output

Close the Terminal window.
Then, open the MyCelesteMod folder that is inside Mods.

To open the mod project, double click the solution (.sln) file.

Linux/macOS

Open Terminal.

If you have never made a code mod before, you need to install the template. Enter the below into Terminal and press Enter.

dotnet new install CelesteMod.Templates

Tip

Remember to run dotnet new update every now and then, to make sure your code mod template is up to date.

Then, to actually use the template, navigate to your Celeste/Mods folder with cd, and enter the commands below.
Remember to replace MyCelesteMod with your mod name.

mkdir MyCelesteMod
cd MyCelesteMod
dotnet new celestemod

Close the Terminal window.
Then, open the MyCelesteMod folder that is inside your Mods folder.

To open the mod project, double click the solution (.sln) file.

Module class

For your mod to load, you have to create a class extending EverestModule in your project. (You can leave Load() and Unload() methods empty if you don't need them though.)

Your module class should look similar to the example.

Note

This example only shows a subset of Everest's capabilities.
See ExampleMod/ExampleModule for more of what Everest can do. 🔗

// Example usings.
using Celeste.Mod.UI;
using FMOD.Studio;
using Microsoft.Xna.Framework;
using Monocle;
using Celeste;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Celeste.Mod.Example {
    public class ExampleModule : EverestModule {

        // Only one alive module instance can exist at any given time.
        public static ExampleModule Instance;

        public ExampleModule() {
            Instance = this;
        }

        // Check the next section for more information about mod settings, save data and session.
        // Those are optional: if you don't need one of those, you can remove it from the module.

        // If you need to store settings:
        public override Type SettingsType => typeof(ExampleModuleSettings);
        public static ExampleModuleSettings Settings => (ExampleModuleSettings) Instance._Settings;

        // If you need to store save data:
        public override Type SaveDataType => typeof(ExampleModuleSaveData);
        public static ExampleModuleSaveData SaveData => (ExampleModuleSaveData) Instance._SaveData;

        // If you need to store session data:
        public override Type SessionType => typeof(ExampleModuleSession);
        public static ExampleModuleSession Session => (ExampleModuleSession) Instance._Session;

        // Set up any hooks, event handlers and your mod in general here.
        // Load runs before Celeste itself has initialized properly.
        public override void Load() {
        }

        // Optional, initialize anything after Celeste has initialized itself properly.
        public override void Initialize() {
        }

        // Optional, do anything requiring either the Celeste or mod content here.
        public override void LoadContent(bool firstLoad) {
        }

        // Unload the entirety of your mod's content. Free up any native resources.
        public override void Unload() {
        }

    }
}

Mod settings, session and save data

Mods can define several classes to save extra data:

  • Mod settings (EverestModuleSettings): for global data (for example settings). Those can appear in Mod Options, and are saved in Saves/modsettings-[modname].celeste.
  • Mod save data (EverestModuleSaveData): for data that is specific to a save file (if the player loads another save, other save data will be used). Can be useful to save stats or the player's progress for example. Saved in Saves/[savenumber]-modsave-[modname].celeste.
  • Mod session (EverestModuleSession): for data that is specific to a play session. This is reset each time the player starts a level, so this is reset if the player restarts the chapter, but is saved if they choose to save & quit. Can be useful to save the state of an entity for example. Saved in Saves/[savenumber]-modsession-[modname].celeste.

Your settings class should look similar to the example.

Save data and session classes are very similar, but inherit from EverestModuleSaveData / EverestModuleSession and the Setting* attributes are ignored.

Important

All entries must be properties, unless you're overriding Load/SaveSettings, Read/Write/Deserialize/SerializeSaveData and Read/Write/Deserialize/SerializeSession to bypass YamlDotNet's restrictions.

Note

This example only shows a subset of Everest's capabilities.
See the Mod Settings wiki page and ExampleMod/ExampleModuleSettings 🔗 for more of what can be done with mod settings.

// Example usings.
using Celeste;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YamlDotNet.Serialization;

namespace Celeste.Mod.Example {
    // If no SettingName is applied, it defaults to
    // modoptions_[typename without settings]_title
    // The value is then used to look up the UI text in the dialog files.
    // If no dialog text can be found, Everest shows a prettified mod name instead.
    [SettingName("modoptions_examplemodule_title")]
    public class ExampleModuleSettings : EverestModuleSettings { 

        // SettingName also works on props, defaulting to
        // modoptions_[typename without settings]_[propname]

        // Example ON / OFF property with a default value.
        public bool ExampleSwitch { get; set; } = false;

        [SettingIgnore] // Hide from the options menu, but still load / save it.
        public string ExampleHidden { get; set; } = "";

        [SettingRange(0, 10)] // Allow choosing a value from 0 (inclusive) to 10 (inclusive).
        public int ExampleSlider { get; set; } = 5;

        [SettingRange(0, 10)]
        [SettingInGame(false)] // Only show this in the main menu.
        public int ExampleMainMenuSlider { get; set; } = 5;

        [SettingRange(0, 10)]
        [SettingInGame(true)] // Only show this in the in-game menu.
        public int ExampleInGameSlider { get; set; } = 5;

        [YamlIgnore] // Don't load / save it, but show it in the options menu.
        [SettingNeedsRelaunch] // Tell the user to restart for changes to take effect.
        public bool LaunchInDebugMode {
            get {
                return Settings.Instance.LaunchInDebugMode;
            }
            set {
                Settings.Instance.LaunchInDebugMode = value;
            }
        }

        // Example string property. Selecting it will show a file naming-like menu.
        // Max length defaults to 12 if the attribute is not set.
        [SettingMaxLength(40)]
        public string ExampleString { get; set; } = "test";

        public int SomethingWeird { get; set; } = 42;

        // Custom entry creation methods are always called Create[propname]Entry
        // and offer an alternative to overriding CreateModMenuSection in your module class.
        public void CreateSomethingWeirdEntry(TextMenu menu, bool inGame) {
            // Create your own menu entry here.
            // Maybe you want to create a toggle for an int property?
        }

    }
}
⚠️ **GitHub.com Fallback** ⚠️