-
Notifications
You must be signed in to change notification settings - Fork 6
Creating Mods
If you have some level of familiarity with C#, getting started making mods should not be too difficult.
- Make a new .NET library against .NET version 4.7.2.
- Add ResoniteModLoader.dll as a reference and optionally HarmonyLib (0harmony.dll)
- Remove the reference to
System.Net.Http
if it was added automatically as it will make the compiler angry - Add references to Resonite libraries as needed from
\Resonite\Resonite_Data\Managed
You'll likely want to grab a decompiler if you don't have one already to take a look at existing code. Here are a few popular options:
Called once per mod during FrooxEngine initialization. This is where you will set up and apply any harmony patches or setup anything your mod will need.
Happens before OnEngineInit()
- Load Locales
- Configs
- Plugin initialization
Happens after OnEngineInit()
- Input/Head device setup
- Local DB initialization
- Networking initialization
- Audio initialization
- SkyFrost Interface
- RunPostInit
- Worlds loading, including Local home and Userspace
Here is a typical usage:
public override void OnEngineInit() {
//If you don't need any configs, these 2 can be left out
Config = GetConfiguration(); //Get the current ModConfiguration for this mod.
Config.Save(true); //If you'd like to save the default config values to file, otherwise you can omit this
Harmony harmony = new Harmony("com.example.ExampleMod"); //this is your instance of harmony, all your patches should be applied using this.
//typically a reverse domain name is used here (https://en.wikipedia.org/wiki/Reverse_domain_name_notation)
harmony.PatchAll(); // Will patch all patches that you've setup with annotations.
}
Harmony docs on patching using annotations.
If you rely on another mod or some of the other FrooxEngine systems to be done initializing before doing something, move the dependant code to load later after all the mods have had a chance to start. This is done with Engine.Current.RunPostInit
added in your OnEngineInit()
, here are 2 examples.
Engine.Current.RunPostInit(FunctionToCall);
OR
Engine.Current.RunPostInit(() => {
//Code to call after Initialization
FunctionToCall();
AnotherFunctionToCall();
});
ResoniteModLoader provides a built-in configuration system that can be used to persist configuration values for mods. More information is available on the Config System page.
using HarmonyLib; // HarmonyLib comes included with a ResoniteModLoader install
using ResoniteModLoader;
using System;
using System.Reflection;
namespace ExampleMod;
public class ExampleMod : ResoniteMod {
public override string Name => "ExampleMod";
public override string Author => "YourNameHere";
public override string Version => "1.0.0"; //Version of the mod, should match the AssemblyVersion
public override string Link => "https://github.com/YourNameHere/ExampleMod"; // Optional link to a repo where this mod would be located
[AutoRegisterConfigKey]
private static readonly ModConfigurationKey<bool> enabled = new ModConfigurationKey<bool>("enabled", "Should the mod be enabled", () => true); //Optional config settings
private static ModConfiguration Config; //If you use config settings, this will be where you interface with them.
public override void OnEngineInit() {
Config = GetConfiguration(); //Get the current ModConfiguration for this mod
Config.Save(true); //If you'd like to save the default config values to file
Harmony harmony = new Harmony("com.example.ExampleMod"); //typically a reverse domain name is used here (https://en.wikipedia.org/wiki/Reverse_domain_name_notation)
harmony.PatchAll(); // do whatever LibHarmony patching you need, this will patch all [HarmonyPatch()] instances
//Various log methods provided by the mod loader, below is an example of how they will look
//3:14:42 AM.069 ( -1 FPS) [INFO] [ResoniteModLoader/ExampleMod] a regular log
Debug("a debug log");
Msg("a regular log");
Warn("a warn log");
Error("an error log");
}
//Example of how a HarmonyPatch can be formatted, Note that the following isn't a real patch and will not compile.
[HarmonyPatch(typeof(ClassNameHere), "MethodNameHere")]
class ClassNameHere_MethodNameHere_Patch {
//Postfix() here will be automatically applied as a PostFix Patch
static void Postfix(ClassName __instance) {
if(!Config.GetValue(enabled)) {//Use Config.GetValue() to use the ModConfigurationKey defined earlier
return; //In this example if the mod is not enabled, we'll just return before doing anything
}
//Do stuff after everything in the original MethodName has run.
}
}
}
Add the following into your .csproj
file.
<ItemGroup>
<Using Remove="System.Net.Http" />
</ItemGroup>
If you have a compiler error mentioning a specific feature is not available in the current C# language, you will need to update your project to use a newer LangVersion
. To do so, edit your project file and set LangVersion
to the version specified or later. Refer to the Microsoft documentation for available versions.
Add or change the following in your .csproj
file. Ensure you only have one entry for this.
<LangVersion>10.0</LangVersion>
Example error:
Error CS8773 Feature 'file-scoped namespace' is not available in C# 7.3. Please use language version 10.0 or greater.