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.