Custom Music

Status Development Source
Finished Maintenance GitHub

Premise

As much as I enjoy the music of RimWorld, at times it can become a little repetitive. So I wanted to create a mod that allows for some more variety. This is my second RimWorld mod, created with the help of the great folks in the #rimworld-mod-development channel on the RimWorld Discord.

This was my first larger project with C# and helped me a lot in getting a grasp of the more advanced concepts of the language, like reflection.

RimWorld features an interesting concept for playing situational music. Each track has metadata attached, telling the game in which circumstances it is available for random selection. This way songs can be restricted to certain seasons, times of day and peaceful or tense situations. Furthermore the playback volume and relative probability of each song can be configured.

When I first thought about adding more music to the game there already were some mods that added new songs. But those were finished packages with a bunch of songs and the required metadata. There wasn’t any way to add new songs yourself.

I could have settled with just copying the songs to the game directory and adding the metadata manually. All the game’s configurations are written in XML, so that wouldn’t have been overly complicated. But where’s the fun in that?

So I set out to create the be-all-end-all of music mods for RimWorld. A mod that allows loading songs from anywhere in your filesystem, configuring their metadata to your preference and playing them interspersed with the vanilla music, according to the same rules.

Development

I wanted the configurations to be persistent and the songs to be remembered. No one wants to re-add and re-configure their music every time they play.
So I needed a custom Def that would be stored in the mod’s settings and that would be compatible to the game’s SongDef so the game would be able to just use metadata the same way it handles the vanilla music.
I also wanted to be able to preview songs while configuring in order to make it easier to suitably set the metadata. Ideally, this would’ve played only a snippet of a song, but I was unable to find a way to limit the playback time for a started song.

Screenshot of the directory browser The mod required a way to find the songs so I needed a way to configure the source path for the additional songs. During initial development I simply used a text field to enter a path, but it quickly became obvious that I wanted something more convenient and robust.
The mod crashed when an invalid or incomplete path was entered, which could easily happen if one wasn’t typing quickly enough.
So I needed the input to be validated and the mod had to fail softly in case of incorrect input. Yay, defensive programming!
I ended up implementing a simple file browser that allows navigating to the desired location. Once a path is selected or entered manually, the directory is searched recursively for OGG files that are then added to the mod’s library.
All this was conveniently achieved with C#’s integrated capabilities.

Screenshot of the library The metadata configuration was split in two parts, with what I assumed to be the most commonly used options living right in the library view, while the rest are only available in the advanced menu.

Quite some time was spent on getting the various windows to look the way I wanted, as RimWorld’s interfaces are built up of rectangles that usually have to be positioned manually. Very 90’s.

Screenshot of the advanced configuration When I started developing this mod the current version of RimWorld was 0.17. With this version I was able to directly hook into the game’s MusicManager to get it to play my songs. With the 0.18 update this was no longer possible, which necessitated the introduction of Harmony, a library that allows for the non-destructive modification of the runtime behaviour of C# assemblies.

Difficulties

  • Unity’s OGG decoder is rather fragile and a malformed file can result in the song not playing in the best case and all custom songs not playing in the worst. I haven’t been able to find a way around this issue, yet.
  • The time required to load larger libraries could significantly increase the game’s start time. This was worked around by not loading all songs at once at the start, but instead starting to stream them once a song is queued for playback, which also significantly reduces the mod’s memory footprint.
  • Unity only plays OGG files. Despite OGG delivering better audio quality at a given filesize and being FOSS, MP3 is much more commonly used. So much in fact, that many users haven’t even heard of OGG. With the MP3 patent expired I may add support for MP3 to custom music once I find a decent, compatible, FOSS and suitably licensed MP3 decoder.

Synopsis

I’m happy with how the project turned out. It’s as well polished as I could wish, blending with the game’s general look. I consider the current version feature-complete. The few shortcomings it has are out of my hands.