Creating A Moddable Unity Game

Creating A Moddable Unity Game
Photo by Hunter Haley on Unsplash

Last Update: Jan 6, 2022. This is the final update of this post as I may be switching my projects to a different game engine

I love games that are moddable. I don't usually mod games until after I've experienced the vanilla version of the game the way the devs intended. If I do use or create a mod, it's usually to balance the game a certain way, or to improve on or add features to enhance my enjoyability of the game.

I used to wonder why many game developers didn't make their games moddable, or made very limited parts of the game moddable. Why wouldn't they make customization available to their customers? Wouldn't it help with their sales (if they didn't consider themselves competing with mods)? How hard could it be to make a game more moddable?

Turns out, I was very naive. It's hard and very time consuming. I apologize to all the devs I've silently complained about. It's not impossible of course, but it requires developing your entire game around the concept. I've probably spent more time trying to make my game moddable than developing the gameplay. It literally would be SO MUCH EASIER to not make a moddable game, especially in the Unity engine which is designed to make heavy use of the inspector. But in designing around the idea of mods, I've learned quite a lot about development and the Unity engine.

There are many companies who've created moddable games successfully with Unity, like Kerbal Space Program and Cities: Skylines. From what I understand, they created proprietary tools or scripts for mod creation. As a lone budding indie developer, I currently don't have the expertise and technical know-how to create extensive modding tools.

What follows is my current understanding of making a moddable Unity game, and the solutions I'm sticking with after much trial and error. This is a general overview, and won't go much into code examples, as there are many tutorials on the internet for that. I'll first start with a few frameworks for Unity that could help with the whole modding process. Then I'll describe the individual areas that need to be made moddable: data, models, textures, animations, audio, scripting, etc. I am NOT affiliated with any site or asset I link to below.

Frameworks

There are a few assets in Unity's Asset Store that seem to handle a lot of the heavy lifting of making a game moddable for you, such as uMod 2.0 and ModTool

I haven't used either of these as I'm trying to rely on 3rd party assets less and less, but the reviews they have seem to indicate they're useful. They both claim to handle adding C# scripts as mods, which is something Unity does not natively do.

In addition, there is a website and service called mod.io,  made by the team behind IndieDB and ModDB. While mod.io requires you to make your game moddable first, it allows you a place to host your mods and make them easily viewable/installable by users. I have not used this either, but may consider it when I'm at that stage of development.

Data

To make the data part of a game moddable, you have to expose the data to the users. If they make changes to the data, you have to be able to load those changes into the game at runtime. There are many ways of doing this. You could use .ini or .txt files, and use some kind of parser to read in the data at runtime. You can also use formats like XML or JSON to do the same. There are still yet other ways, like using a database such as SQLite or even Google Sheets, and using a 3rd party or proprietary system to convert the database to usable data for your game. Essentially, whatever you choose should be easily creatable and editable. There are many assets on the Unity Asset Store which handle the loading of each of the above-mentioned file formats.

After much Unity Asset store browsing and shopping as well as testing, I settled on using JSON files. After reading countless XML vs JSON articles on the web, I settled on JSON for 5 reasons:

  1. Unity has a built-in JSON serializer - it does everything I need save for one thing: it does not serialize enums to strings. I've requested this a few times from Unity's developers, but I don't think it's a priority for them. You can try handling this yourself during serialization (which I haven’t attempted) or just document the integers which the enums are converted to, for modders.
  2. It has a concise, simple, human readable format that should prove easy for users to modify, especially if it's output in pretty format.
  3. In certain situations, it seems like json can be faster to read and parse than XML.
  4. It can be easily editable using free text editors like Visual Studio Code, Notepad++, Brackets, Atom.
  5. It seems to be fairly popular, especially in web development.

If you're not happy with Unity's built-in solution, there are a ton of JSON solutions in the Unity Asset Store, for example Json.NET, which is free. Just do a search in the store for "json" or even "xml" if that's what you've decided to use. You can also search for "ini" or "SQL" as well. There are other free JSON frameworks, like Json.NET, LitJSON, etc, but they may not be designed specifically for use with Unity, and depending on the platform you're developing for, may not work correctly. Also, according to this Unity forum thread, Unity is working on .NET upgrades, which could make the System.Text.Json API available in the future.

If you create a class in Unity with some data in it, you can use one of these JSON frameworks to serialize the class object to a string. Then you use methods from System.IO like File.WriteAllText() to write the data to a file. To read it back in, you use something like File.ReadAllText(), and deserialize the result back to an object of the original class. For specifics, see the documentation of the framework you're using.

Ok great, we can create files and load them back in to the system. But other than explicitly initializing the class members in code, how do we create and edit the data in a nice, easy way, to then be serialized and exported to a file? There may be solutions for that on the Asset Store as well, like some which let you edit data in Google Sheets and then can export that data into JSON or some other format if you'd like, which you would then read into your game.

I decided to go the way of using a Unity-provided solution: ScriptableObjects. One use of ScriptableObjects is as an in-editor database which uses the inspector, and whose data can be shared at runtime. But I'm using it slightly differently in that I'm serializing the data from the ScriptableObject to a file (in the StreamingAssets folder) in the editor while developing, and then I read the data back into a class from that file at runtime. There are many learning resources on the Unity website for how to use ScriptableObjects, so if you're not familiar with them, please see those tutorials. I'm using the handy asset Odin from the AssetStore to quickly create inspector UIs for the ScriptableObject databases using simple attributes, for example buttons in the inspector to serialize the data to a file.

Using this system of entering and editing data in the inspector of a ScriptableObject, pressing a button to serialize the data to a file, and implementing some runtime GameObject managers to deserialize the data from files back into the ScriptableObjects in the loading screen was working perfectly. I have JSON files for configuration data, and all kinds of unit and weapon data. Ah, but what if a user wants to have multiple mods? If different mods edit the same JSON files, won't they overwrite each other? Ok, now we need to create some modding directories.

Using two different Unity provided directories, we can handle this easily. The solution I came up with is to provide all my JSON files that come with the game in Unity's StreamingAssets folder. Essentially this will be the vanilla “mod” that ships with the game and that the game uses by default. Users can mod those files, but then we would lose the original data. So using Unity's PersistentData folder (which varies on different platforms), we can allow mod folders which parallel the structure of the StreamingAssets directory. The game checks first to see which mod folder is the one we want to use, then checks if a specific file exists in the mod folder. If not, we load the original one from the StreamingAssets directory. Nice.

Originally, I wanted to create mod folders within the game install directory, but that doesn't work well on different platforms. Some directories which the game may be installed to may not be writable at runtime, and thus we have to use Application.persistentDataPath.

Models and Animations

Ok, now for models (meshes) and animations. Fortunately with the latest versions of Unity, we can still use AssetBundles to load content very fast. Users can create their own AssetBundles for inclusion into a game, provided they are set up in a specific way for a particular game. This is the route I'm taking with meshes, but you'll have to document everything for your particular setup. While there is support in the inspector for creating AssetBundles, you can also use Unity's AssetBundle Manager package to quickly organize your bundles, but be aware that it is no longer being actively developed. I load a particular AssetBundle based on its path and filename, so I enter that path in an entry in the moddable data, and load the AssetBundle via the AssetBundle API after it has been built.

There is a new way of loading content in Unity called, Addressables. I want to note here that as of the latest update of this blog post, modding is very complicated to set up with Addressables. As you can see from this and this and this thread in Unity's forum, using it in a way to support mods is not documented yet. However, I did find a tutorial recently for how to do just that, and you can find it here: https://www.raywenderlich.com/14494028-introduction-to-modding-unity-games-with-addressables . I also came upon this post on the Unity forums, which could possibly make Addressables more modding friendly.

To me, Addressables currently has 3 drawbacks. The first is needing modders to create content catalogs using the Addressables system, and managing the loading orders of that seems to create more hassle than just using AssetBundles directly (Addressables currently uses the AssetBundles API underneath for now. Unity mentioned some time back that they were planning to replace AssetBundles, but that hasn’t happened so far). Second, I haven’t figured out a way to be able to just load all Addressables built AssetBundles in a directory, since Addressables seems to require an address for an asset. Third, I also found that Addressables was not offering me the customizability that I wanted without having to modify parts of its included code, and that might be a pain to update every time the Addressables package gets updated. Although your use case may vary, I’ve decided to stick with using the AssetBundle API directly, as it’s easier to get mods to work via replacement without having to require modders to create additional content catalogs. I just hope that Unity doesn’t decide to deprecate AssetBundles in the near future.

If you don't want to create AssetBundles, other options include using runtime model importers available in the Asset Store, like .fbx, .obj and .gltf file importers. The problem with .obj files are that they can't include animations, so if you're not including animations with your model, you're OK. Do a search on the Asset Store for "fbx" or "obj" or "gltf" and "import" to see various options. Since I'm not using characters in my current game, I decided to develop animations within Unity, as opposed to creating them in a separate modeling program like Maya, Max, Modo, Blender or Houdini. The solution I came up with is to create animations using the Mecanim system and Animations window, and include those animations as an AssetBundle. This way, users can create their own animations as AssetBundles, and provided they are set up in the same way, I can load them into the game at runtime using AnimatorOverrideController. What will be required, though, is good documentation on how to do it once the game is released.

Textures

Now onto textures. Well, this is a little tricky and requires trade-offs. From what I can tell, there are two main ways of doing this: AssetBundles (or Addressables), and loading images as files. Using Unity's ImageConversion.LoadImage() method (or UnityWebRequest.GetTexture() if on the web), we can load an image (.jpeg or .png) from the file system. Using workarounds to create temporary textures which are replaced by these methods, we can specify the attributes and compression of the textures. The problem with this is that loading textures, especially larger sizes like 4096x4096, results in VERY LONG load times. I noticed that there is a much larger use of graphics memory with loading textures this way as well, possibly because they aren’t compressed. Some special care is also needed for dealing with normal maps when loading images from files.

The other method is using AssetBundles again, which allows you to specify the texture import settings and compression in the Inspector. Loading these AssetBundles at runtime is extremely fast, as the textures are already processed in a way that Unity can use. But modders can't simply open AssetBundles and edit the contents inside. So, to sum up:

Loading .jpeg or .png files from the file system:

  • Allows users to edit or replace textures easily
  • Results in very long load times for larger textures unless done asynchronously, and may use more graphics memory,
  • Requires workarounds for normal maps

vs.

Loading AssetBundles from the file system:

  • Easily set texture import and compression settings in the inspector by the developer or modder
  • Very fast loading times
  • Very difficult for users to modify provided textures, unless you use 3rd party tools to extract AssetBundle contents (see below)
  • Somewhat difficult for modders to build their own texture AssetBundles for use in-game if they’re not familiar with Unity.

There are a couple of 3rd party solutions to extract the contents of AssetBundles, which can be found by searching "assetbundle extractor" on Google. I haven't tried any of them yet, but I'm hoping by the time my game is released, these tools will be more robust, or Unity will provide its own solution (not likely, as other game developers may not want their proprietary assets being extracted from AssetBundles).

There is another solution to the difficulty of extracting assets from AssetBundles. Just make available or distribute those assets separately, meaning, if I have a texture packed into an AssetBundle, I could make the same texture available outside of the AssetBundle. It won't ever be used by the game, and will increase the distribution size of the game, but at least the user will have access to it.

I chose the AssetBundle route, because the long load times otherwise was too unbearable during testing, and I believe that any additional work should be done by the developer and modders, rather than making players wait for load times.

Audio

I was able to implement runtime audio clip loading, and again there are a couple of options. We can use UnityWebRequestMultimedia.GetAudioClip() to load clips in their raw or compressed formats like .wav, .ogg, or .mp3, or again use AssetBundles. I went the AssetBundle route again, so I and any modders can set compression/streaming settings appropriately for the clips, depending on their size. I'll again have to provide documentation for this.

Scripting

As mentioned in the "Frameworks" section above, there are some assets in the Asset Store which allow loading C# scripts at runtime. There are also assets which allow Lua scripts to be loaded at runtime, if you're familiar with that language. I'm not sure if I am going to allow script modding, as I don't even know if anyone would even want to do script mods for my game. I will probably revisit this idea in the future if it makes sense to do so, especially after I decide how my mission scripting will be done.

For anyone interested, some options include Lua frameworks for Unity , the proprietary MiniScript, and for C#, Dynamic C# or Roslyn C# Runtime Compiler.

Conclusion

There are many different ways to include modding support. What I described above are my current solutions, which could change at any time. One thing for sure is that if going the AssetBundle route, I'll have to provide detailed documentation for users on how to create AssetBundles to be used correctly with my game.

As there are so many different solutions, each comes with advantages and disadvantages for the developer and user. It's a balancing act in terms of time, usability, and productiveness. I just wanted to say "THANK YOU" to the developers of all the games I've ever played with modding support. After stepping into your shoes, I truly appreciate the required time and effort.

Update: Jan. 6, 2022, Just found this reddit post with even more ideas about how to do this in Unity.

Comments

The comments shown below are from visitors when I was using Squarespace for website hosting, but I've switched to cheaper hosting with a different CMS and currently have registering/commenting disabled. Since this post tends to get a lot of traffic, I've copy/pasted all past comments in case they may be useful for someone.

MichaelEGA 2023

Thanks, easy and clear. Will be implementing some of these ideas in the future.

Sean Kumar 2023

Thank you for taking the time to comment!

Janik 2022

Thanks for this amazing post. Im building my game with modding aswell and I am not at the point where I need to think about what would happen if the user has 2-3 mods installed which all edit the same files. How do other games handle this?

Sean Kumar 2022

Hey! I can think of two ways to handle this, though there are likely more. The first is to control ordering of loading certain files and folders, overwriting any previously loaded file/folder. Depending on how your game files are setup, if your game has all files in one directory, or even a folder per mod, the game could detect all the files or folders that exist in a directory, display them in-game in the UI as a reorderable list, the user rearranges the order as they want, and then the game could load the files or folders in the specified order.

The second way, which is the way I'm doing it, is to require one mod per folder in the persistentDataPath. The vanilla base game without mods exists in a directory tree in the StreamingAssets folder. Any mod folder in the persistentDataPath needs to follow the same directory structure layout as StreamingAssets. However, not every file or folder that exists in the base game needs to exist in the mod folder, only altered or changed ones. Then, in a config file, I have a field which says which mod folder to load, or none. The game, when loading all the data files, first checks the mod folder for a file if it exists, and if not, loads the StreamingAssets base version. The user can either edit the config file directly to choose the mod, or in-game I have an option in the UI to list all the mod folders that exist in the persistentDataPath. In that UI, the user can can select which mod folder they want to use, and then they can click a "Load" button which reloads the scene, which then reloads all the data checking if any altered version exists in that mod folder.

This would handle big mods easily, but not necessarily small mods. If they have multiple smaller mods that alter the same thing, they could potentially create a mod folder where they put all kinds of conflicting mods, and would have to paste them in, overwriting based on the order they want, but as I'm writing this I'm feeling that that's not such an elegant solution for the user, and in this case, the first solution above may be better.

Hope this gives you some ideas on how you might want to do it for your game!
Janik 2022

Thanks a lot for this quick answer. I believe you noticed aswell now how 'hard' this sorting problem is.
What I came up with in combination with your answer is this:
Have each mod it's own folder in a modding folder in persistantDataPath.
Each Mod has the same directory structure as the base game data in StreamingAssets.

When you start the game, you'll be shown all mods BUT you can also select and deselect each individual section in the mod.
For example: Mod A modifies and adds Weapons, so only a weapon folder exists in the Mod.
But Mod B modifies or adds Weapons AND adds new sounds to soldiers. So Mod B has 2 different things.
In the Menu now see user can see when he clicks on more information about one mod, that Mod B alters 2 sections in the game. The user can then disable for example the Weapons part. So only the Weapon part from Mod A gets loaded.

This gives a clear overview over every mod and what they edited aswell gives the user the controll to choose what to activate and what not. So the user can fix some problems himself if any occur.
Sean Kumar 2022

Sounds like a good plan! It could get a little hairy if you have some files in the Weapons folder that are changed in one mod, and different ones in the same Weapons folder in another mod, and you don't know what exactly is changed in each, but how complex or easy it is depends on how you're setting up the mod files. I guess you could get really granular and list every file that is changed in a mod with a checkbox to enable it within the game, but I can imagine that being a pretty big UI headache if you have lots of files. That might be something easier to implement in an external mod manager. It's great to hear how others are coming up with their own solutions, so thanks for contributing!

Adam 2022

I stumbled onto this post whilst looking into how to get DataPath to work for mods on android! :) I can confirm there are issues with it on different platforms! :) Thank you, this was a really interesting read, I will likely bite the bullet and make android use persistentdata like you! Thank you again

Sean Kumar 2022

Thanks for taking the time to comment! I ran into problems with Application.dataPath on PC which persistentDataPath solved, too. I've never done a build for Android, so it's good to hear your confirmation about problems with it there as well.

Athaeus 2021

Updating a blog post after four years after circumstances change is the kind of dedication I love to see. That was INCREDIBLY helpful, mate, hank you. I would barely have an idea as to what I can even do to allow modding if it weren't for this neat and tidy overview. Just discovered your game, by the way. Hugely interested. I'll be keeping an eye on this website! Thanks again!

Sean Kumar 3 years ago

Thanks for posting and for the kind comments! Really appreciate it!

Kyle 2021

It's pretty easy to load regular Unity C# via asset bundle. You take your Unity project's C# DLL and rename it xxx.bytes and throw it in an asset bundle. Then the first thing you do when loading an asset bundle is find those .bytes files and do Assembly.Load(), then when you spawn prefabs that reference the scripts they are automatically loaded and configured.

Anonymous 2020

Hey!
This was a super great read and had a lot of info to point me in good directions that I really wasn't finding in other corners of the internet.
Thanks!

Sean Kumar 2020

That's really great to hear! It's good to know that this post is useful for developers. Thank you for leaving a comment.

LichKingNZ 2020

Great stuff! Waiting for your update to this post. Maybe some code as examples =)

Sean Kumar 2020

Thanks for commenting! Code examples could be really useful. I'll see what I can do in a few days.Edit: After updating this article, unfortunately I'm going to have to take back that statement... While code examples would be useful, trying to include them would mean showing A LOT of code to demonstrate it properly. Fortunately there are already many many tutorials, posts in Unity's forums, or blogs which do that for each of the sections above. Sorry about that! If there's something specific you're looking for that you're having trouble figuring out how to do, please let me know.

totesmagotes 2018

For Game Data Editor, what's the recommended way of using it? Do you have to import all of that stuff into your project, and use it inside your project? If so, how do you allow your users to use it? Can you just import it into a brand new project, build it, then use that other app as an editor for the data in your game? If so, are you even allowed to package that as a "mod tool" for your game?

Sean Kumar 2018

Hi, I haven't used GDE but from what I gather from their Asset Store page and documentation (http://gamedataeditor.com/en/docs/gde-quickstart.html) , you do have to import their asset into your project and use it there, mainly for the features in the Unity Editor. It looks like it generates a text file which you include in the build of your game. You would need to make sure you get your data only from that text file, so your users would just need to modify the text file to mod the game's data, and they wouldn't even need the GDE Asset.It may be possible for your users to use the free version of GDE to modify the text file, but I'm not sure. You may want to download it and give it a try to see how that would work.If you're looking for some sort of existing editor for your users to edit game data, you may want to look into a database solution like SQL (see SimpleSQL in the Asset Store), where there are free existing editors for different OS's which can browse and edit the database.Having said all of that, it's kind of nice to use Unity's built-in ScriptableObjects and JsonUtility to edit your game's database and export it to a file, which you access at runtime. Your users would only need to edit the JSON files to modify game data.I'm going to update this post with a little bit of new info, as it's a couple of years out of date.

khan 2017

Thanks for this blog :)

Sean Kumar 2017

Thank you for visiting!