Harmony DLL's

Image

 

Click image to return to Home

Image

 

Harmony DLL's

Using the principles learnt in the Creating Old World Mods tutorial, this tutorial will take you through the requirements of setting up a DLL mod that supports Harmony. Harmony is a 3rd party library for patching, replacing and decorating .NET and Mono methods during runtime.

Tutorial

Up to now, the DLL modding I have demonstrated on this site required the overriding of the GameFactory class to create your own separate GameFactory object. In the previous tutorial Putting it all Together we did this by the following line of code.

modSettings.Factory = new CharacterListGameFactory()
                                

This allowed you to have your own custom classes and methods to override the default ones. However this does present an issue in Old World as only one mod is able to completely override the GameFactory class. Players in Old World are allowed to enable multiple mods for their game setups. If, for example, the player wanted to enable two DLL mods then only one DLL mod would actually work correctly.

How can we get around this? As a mod maker, how can we support other DLL mods to work with ours?

The answer comes in the form of a neat little library called Harmony. Harmony allows the mod maker to inject their custom code into the existing code structure, without the requirement of having to override Old World's GameFactory class. In the library's own words.....

Harmony gives you an elegant and high level way to alter the functionality in applications written in C#. It works great in games and is well established in titles like 7 Days To Die, BattleTech, Besiege, Cities:Skylines, Kerbal Space Program, Oxygen Not Included, Ravenfield, Rimworld, Sheltered, Stardew Valley, Staxel, Subnautica, The Ultimate Nerd Game, Total Miner, Unturned and many more.

And now Old World.

Modding with Harmony

Harmony is a C# library that will need to be added to your project. If you have Nuget then you can install Harmony into your solution via Nuget, otherwise head to their Github page: https://github.com/pardeike/Harmony and get the Harmony DLL that way. If you downloaded Harmony from Github you will have to add 0Harmony.dll as a reference in your project. Nuget automatically does this for you. In both cases you must also copy 0Harmony.dll to your Mod folder (where the modinfo.xml and your built dll reside).

When adding Harmony, make sure to add the using statement to your cs files. Then, in your Mod's Initalise method, instead of creating a new GameFactory instance, create a new Harmony instance. You also need to shut down the Harmony instance via your Mod's Shutdown method. This is done as shown below.

Note: when creating your new Harmony instance it needs to have a unique name. In the example above I used "Dale.SettleAnywhere.patch", I strongly advise that everyone who mods for Old World uses the format "name.modtitle.patch". This will ensure we all avoid duplications amongst the community of Modders.

The next step after initalising a Harmony instance is to setup each patch. In Harmony terms, a patch is the manipulation of a single method of the original code. You can have unlimited patches but each patch can only alter one original method. Each patch needs to be attached to a method in a class within the original code, and then a prefix and postfix defined for each patch. A prefix is code to execute before the original code (with an option to block the original code from executing) and a postfix is code to execute after the original code. Please refer to Harmony documentation for full details: https://harmony.pardeike.net/ or the Harmony Wiki: https://github.com/pardeike/Harmony/wiki.

For this tutorial I will show how to capture the execution of "CreateTile" from the GameFactory class. In the below code, the first line attaches a patch to the GameFactory class, CreateTile method, then the class contains the prefix and postfix methods of the patch. The prefix method does nothing in this instance (I don't want to execute anything before the original code). The postfix method contains code to replace the result of the original method. In this instance I am replaceing the creation of a new tile object, with my custom tile class. I can then define my own tile class methods, such as blocking the urban tile requirement of founding a city so settlers can found anywhere.

Below is the custom Tile class that my patch is using to allow settlers to found a city anywhere.

Where Harmony shines is that you can have as many patches as you need in your mod. Harmony also allows other DLL mods as long as each mod patches different methods. If two mods try to patch the same method, there will be a conflict and only one will work.

Advanced Harmony

Even though the above will work, and opens up for good mod compatibility between DLL mods, there is a better way. The above method blocks the entire Tile class of the game. What if someone else had a mod that also patched a method in Tile using the above methodology? Both wouldn't work together.

So Harmony lets us drill even deeper into the class-method structure within the game. Not only can we patch full classes, we can also patch a single method. Now two mods that patch the Tile class, but different methods can work together.

The code above, changes the Harmony patch to only patch a single method. Not the entire class. So where I patch Tile.isValidFoundLocation, now someone else is able to patch Tile.setResource method without conflicting. The big change is the [HarmonyPatch..] definition. You can define a direct method, including the input types, using this formation of [HarmonyPatch(typeof(class), nameof(method), typeof[] { input types })]. I also used a Prefix, which means my patch executes before the original code. I pass in a reference to the __result, which is the method's return value, the Tile class __instance as well as the method's input types. Remember that the __result is the value returned by the method. The actual return bool from a Prefix defines if the original code executes or not. In my example since I completely patched the method I opted to not run the original code after my patch.

That concludes this tutorial. You should now be able to create DLL mods using Harmony to patch methods. To help support other modders it is recommended to use Harmony as it will allow the greatest set of posibilities for players.

Settle Anywhere Harmony example & mod source files - 24 August 2020