How To Write A Simple Clone Hero Mod (CHLoader) - Biendeo/My-Clone-Hero-Tweaks GitHub Wiki
NOTE: CHLoader simply injects your code into Clone Hero, but it doesn't do anything else beyond that. Installs also include CHAPI, but it seems to not have been updated for use for v23.2.2. I encourage using BepInEx for new mods as it contains some useful libraries to help you create your mods.
How does CHLoader work?
CHLoader is actually quite simple; it simply looks inside the Tweaks
folder in the current directory and creates a list of all the .dll
files in that folder. It then goes through each one to find a class called Loader
, and then tries to create it and invoke its LoadTweak
method. If any errors occur, it just skips that file and continues to the next one.
How to write your own CHLoader tweak
First of all, set up a new project for a C# class library using .NET Framework. I personally pick 4.8, although any version 4.x should do fine.
All you need to create a tweak is a file called Loader.cs
which is structured as such:
namespace MyCoolTweak {
public class Loader {
public void LoadTweak() {
}
public void UnloadTweak() {
}
}
}
It is important that the class is called Loader
, and it contains two public void
methods called LoadTweak
and UnloadTweak
. When the tweak is loaded, it will call LoadTweak
. From here on out, it is up to you to implement instantiating and defining how your mod works.
A typical implementation of Loader
could be like this (taken from Extra Song UI):
namespace ExtraSongUI {
public class Loader {
public void LoadTweak() {
WrapperBase.InitializeLoaders();
if (this.gameObject != null) {
return;
}
this.gameObject = new GameObject("Biendeo Tweak - Extra Song UI", new Type[]
{
typeof(SongUI)
});
UnityEngine.Object.DontDestroyOnLoad(this.gameObject);
this.gameObject.SetActive(true);
}
public void UnloadTweak() {
if (this.gameObject != null) {
UnityEngine.Object.DestroyImmediate(this.gameObject);
this.gameObject = null;
}
}
private static GameObject gameObject;
}
}
In this example, the loader has a static instance of a GameObject
so that it knows whether the mod is loaded or not. Please note that Loader
has a transient lifetime, so a new instance is created every time the tweak is loaded and unloaded. The LoadTweak
method checks whether this object has been instantiated, and if not, creates a new one with a component defined elsewhere in the assembly. Because there is now a GameObject
instantiated, Unity will run its behaviour. In this example, the SongUI
component inherits from MonoBehaviour
and does work in its LateUpdate
method, which Unity calls at the end of every frame. UnloadTweak
works similarly, but destroys the GameObject
if it exists instead.