Code Mod Setup - coloursofnoise/Resources GitHub Wiki
- Everest: https://everestapi.github.io/
- Visual Studio 2015 or newer or another IDE with C# language support, or the cross-platform dotnet cli:link:. You need to have the .NET Framework >=4.5.2 targeting pack installed. If you are using Visual Studio 2022 (latest), either install the .NET Framework 4.5.2 Targeting Pack manually or install the .NET Framework 4.6 targeting pack and make your library target that instead (if you are using a template, this may require manually editing the
TargetFramework
in your .csproj file).
Every Everest code mod starts out as a C# (.NET Framework) class library targeting the .NET Framework 4.5.2 (same as Celeste itself).
The simplest way to set up a code mod is using a template. Some community created options include:
-
CelesteMod.Templates -
swoolcock
🔗 (for use with the dotnet cli -dotnet new --install CelesteMod.Templates
) - Everest Code Mod Template -
coloursofnoise
🔗 - aridai's Celeste Code Mod Template -
aridai-shi
🔗
This setup doesn't require NuGet or git, but if you're a Windows user, you'll need to switch to the OpenGL branch. Linux and macOS users are already using FNA. Everest will relink your mod from FNA to XNA at runtime.
- In Steam, right-click the game in your library, select "Properties" and select the
opengl
"beta". - In itch, simply install the Celeste Windows OpenGL version.
- Epic Games is already using FNA
Note that it is not necessary to play on the OpenGL version to use mods, so a copy of the game files can be used solely for building mods.
After the update has finished, make sure to reinstall Everest.
- Open your C# IDE (f.e. Visual Studio 2015).
- Create a new project.
- In the top bar, select
.NET Framework 4.5.2
- In the left bar, select
Installed
>Visual C#
- Select the template
Class Library
orClass Library (.NET Framework)
(notStandard
,Core
,Portable
,Universal Windows
, ...). - Create your mod in Celeste/Mods
The dialog should look similar to this:
- Create a new
everest.yaml
text file with the following content:
- Name: YourMod
Version: 1.0.0
DLL: Code/bin/Debug/YourMod.dll
Dependencies:
- Name: Everest
Version: 1.0.0
For more info about the mod structure, the everest.yaml
format, how to add extra content and on how to zip up your mod, read the mod structure page.
- Right-click your project's "References" and select "Add Reference...", then "Browse..." into your Celeste installation directory and setup your references like on the following screenshot (add the relevant references and remove extra ones that got added automatically):
You'll find most of those references as dlls in your Celeste installation directory. "Celeste" is Celeste.exe itself.
Make sure to select all those references, right-click > "Properties" and set "Copy Local" to "False", or you will accidentally include copies of those files in your mod!
If you want to maintain cross-platform compatibility, make sure to only use .NET Framework system libraries (dependencies, not namespaces) from this list.
- System
- System.Configuration
- System.Core
- System.Data
- System.Drawing (available, but behaves unpredictably)
- System.Runtime.Serialization
- System.Security
- System.Xml
- System.Xml.Linq
This means: Microsoft.CSharp, System.Windows.Anything, System.IO.Compression and other libraries must be removed from your references.
For an up-to-date list, check the list of precompiled MonoKickstart libraries:link:, as Celeste uses them for Linux / macOS.
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.
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() {
}
}
}
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 inSaves/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 inSaves/[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 inSaves/[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.
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.
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?
}
}
}