I have no experience, yet, when it comes to making games with modding support. Academia would be my first. To test the waters, I made the easiest type of mod: image replace or “reskin”. In this post, I will describe our set up and how the modding process would be.
In my previous post, I have described that we used StreamingAssets to load our image assets. This is very different from using sprites inside Unity where you drag and drop a sprite asset to a SpriteRenderer. What we do is we load images using Texture2D.LoadImage(), pack them into one big atlas, and assign them to our custom quad, all of these during runtime. The rationale of course is for modding support. We want to be able to load and use images that are specified by a modder.
We maintain an XML file that acts as the database of mapping to image paths under StreamingAssets. It looks like this:
<TileSpriteMapping> ... <!-- Student Chair --> <Entry id="StudentChairDown" streamingPath="BaseGame/Tiles/Objects/ChairStudentDown.png" /> <Entry id="StudentChairUp" streamingPath="BaseGame/Tiles/Objects/ChairStudentUp.png" /> <Entry id="StudentChairLeft" streamingPath="BaseGame/Tiles/Objects/ChairStudentLeft.png" /> <!-- Standard Chair --> <Entry id="ChairDown" streamingPath="BaseGame/Tiles/Objects/ChairStandardDown.png" /> <Entry id="ChairUp" streamingPath="BaseGame/Tiles/Objects/ChairStandardUp.png" /> <Entry id="ChairLeft" streamingPath="BaseGame/Tiles/Objects/ChairStandardLeft.png" /> <!--- Kitchen Sink --> <Entry id="KitchenSinkDown" streamingPath="BaseGame/Tiles/Objects/KitchenSinkDown.png" /> <Entry id="KitchenSinkLeft" streamingPath="BaseGame/Tiles/Objects/KitchenSinkLeft.png" /> <Entry id="KitchenSinkUp" streamingPath="BaseGame/Tiles/Objects/KitchenSinkUp.png" /> ... </TileSpriteMapping>
We then have a manager that parses this file and also handles the loading and delivery of such asset. We can easily get a Sprite or a set of Texture and UV coordinates by using the id of an item in this XML file.
renderer.sprite = SpriteManager.Request("KitchenSinkDown");
To change a particular image, the modder only has to provide his/her rendition of the image and an XML file with the same format as ours. The difference is that the base folder would be the root folder of the mod instead of StreamingAssets. The modder don’t have to specify all entries. The modder only has to specify the entries he/she wishes to change. For example, if a certain modder would like to change the kitchen sink’s image, this could be the his/her XML mapping:
<TileSpriteMapping> <Entry id="KitchenSinkDown" streamingPath="Images/Objects/KitchenSinkGraffitiDown.png" /> <Entry id="KitchenSinkLeft" streamingPath="Images/Objects/KitchenSinkGraffitiLeft.png" /> <Entry id="KitchenSinkUp" streamingPath="Images/Objects/KitchenSinkGraffitiUp.png" /> </TileSpriteMapping>
The modder can organize his/her images however they like. The custom images would be expected in said folders. What the game does is we parse our default base mapping first, then during mod installation, we look for this XML file in every mod folder, parse them if they exist and use their entries to replace the entries in our default mapping. When sprite packing executes, the image paths specified by the mod will be the ones that get loaded. And that’s it. The modder can replace any image in the game easily as long as they are in the XML mapping.
It’s the most readable and easy to understand text format in my opinion. Non programmers can easily understand it. Most importantly, it supports comments. I plan to distribute a sample mod folder that modders can just download and build from. With XML, I can write some documentation within the file itself as comments.
Another benefit is it saves us from making a modding editor application. A custom editor would be nice, but in this case, it’s not really needed. We want to release this simple modding environment as soon as we can.