This post is probably going to be a bore for most, as I’m specifically writing to address developer-type people and maybe the devs themselves… but here goes anyway.
I’m excited about the developer’s stance on modding Airport CEO, but – understanding that it’s an actively developed early access game – not much can be “modded” at this point. In a bout of boredom combined with early morning insomnia I decided to try and get custom C# code injection working, following the modding methods of other Unity-based games.
Before I go on, I’d like to note I was not able to find a license/terms and conditions for Airport CEO (is there even one?) – only one for the website and forum, so I currently don’t know the legality on reverse engineering Airport CEO’s compiled source code. If the devs are against this, I will delete this post and my project files.
Other notable Unity games that allow additions and modifications of code usually do one of these two things, or even both:
- They bundle a compiler (usually Mono.Cecil) with their game and compile mod source code for runtime injection
- They load a compiled library into runtime without bundling a compiler
For example, a notable game that uses option 1 is Swedish developer Colossal Order’s Cities: Skylines.
With Airport CEO being so early in development, it makes sense that there’s no way to inject modded code into the game… so I did it myself anyway, and here’s how:
In a Unity game, most compiled UnityScript code is stored in a library called
Assembly-CSharp.dll that resides inside the
***_data folder. Since C# compiles to IL (intermediate language), this file can be opened using a .NET disassembler, like dnSpy. To get other code loaded into the game, we have to load another assembly file using reflection from inside the game and then override game instances with the modded instances. To accomplish this, I found the earliest possible point I could execute code inside this file and added my DLL loader. You’ll see in the source below that I’m doing the loading in the
Start() function of the
MainMenuUI class (basically the point where all the cool split-flap stuff gets generated on the main menu that you know and love). Once the assembly is loaded, I call the main class inside my modded library and then let Apoapsis’ code continue doing its thing.
From this point in my own “modded DLL file,” I use the popular overriding library Harmony. Used in most other Unity games like Rimworld and Cities: Skylines, this library allows mods to execute code around known methods without touching source code and allows multiple mods to co-exist without touching each other. The only thing my “mod” does is add a message dialog pop-up when you click “New Game” as a proof-of-concept. By compiling my mod and putting it in the Airport CEO base directory (along with the
0harmony.dll file), starting the game will allow harmony to run it’s patches:
In conclusion: If the developers decide to add C# script-style modding, my assumption is they’d probably do it in one of the two ways above. Until then, it is a REAL bad idea to do this on your own since it requires modifying a compiled file the game ships with, and this may be against the Airport CEO terms of service.
The game-side patch to load an assembly:
The mod itself: