New modder questions

Hi, I’m trying to build mods with the Mono build of the game. I’ve gone through initial setup to get MelonLoader mods running and applied to the game, and I’m now trying to get into the functionality of the game. Although I can code, I am new to modding & Unity, and I don’t fully understand how the game managers work or when object initialization is done. From my initial reading of the code, I’m lost on how to extend functionality for the game.

Is it a bad idea to extend a manager like the ResourceManager? When are managers initialized? Should I dive into docs for working with Unity’s game engine? These questions maybe more related to modding for Unity games than for FF specifically. Any pointers on where to look to get started are appreciated. Thanks.

Did you see this?

1 Like

I’ve answered similar questions in discord a couple of times; I guess this is as good a time as any to write an impromptu guide. IMO, if you’ve got everything set up and can print “hello world” onto the MelonLoader terminal (using @gusi’s guide linked above), you’re halfway there already.


There are 2 basic ways of getting a code to run via a mod. Firstly, is to use one of the callbacks provided by MelonLoader. These are methods that get called after specific events, your mod can inherit these and any code you write there will get executed at the appropriate time. Some of these hooks get called after a scene is loaded or even every frame, the existing list is available here. That entire page is well worth a read. These call backs are very easy to use and require only light scripting, but the call backs available are common to all Unity games, so they can be somewhat limited.

The second option is to use HarmonyPatch. This uses C# reflection black magic to let you write a function which gets called just before (or just after, or even replace) any specific method in the entire library of code that makes up the game (specifically in Assembly-CSharp.dll). This is very powerful but can be fiddly for various technical reasons. Again, that link is a pretty concise overview of what it can do, and how to use it; the MelonLoader article linked above explains how the two are integrated.

You might expect that one of the things we could do is to simply modify data files before they’re loaded into the game, ie, that there’s a BuildingData.xml file sitting somewhere and we can just change a number in a text file to increase a building’s range. Sadly, we cannot. We have the code but not the data files. So we have to modify the data after it’s been loaded but before it’s been used; there’s a lot of trial and error in figuring out when that is it different cases.


But to do anything useful with any of that, you’ll need to actually read the code to see what you want to change. I use two different tools for that. To “decompile” and then navigate Assembly-CSharp.dll I use dnSpy. Visual Studio does that itself, but I find dnSpny far nicer for this. The ability to search for classes by name and/or inheritance structure is great, as is the “analyze” function which will find all the cases where a particular method is called. Being able to navigate the in-game memory live is also fantastic - it lets me see what values things are by default, experiment with changes quickly, and verifiy that mods are doing what I want them to. This can be done easily using UnityExplorer - which is functionally a mod that works for all Unity mono games. Especially nice is the ability to click on an in-game object (on the map or in the UI), and inspect it.

In terms of learning Unity, there are loads of tutorials out there. What to learn depends on what you want to do. I’d say that it’s good to have a passing familiarity with what MonoBehaviour, GameObject, Transform, Prefab, and Components are, and the tree like structure that links them; as well as Scenes. There’s no need to become an expert on them, but knowing what these are makes navigating the architecture of the game way easier.


To (finally) answer your question about when managers are initialized - it depends, but fairly late. Often I find they’re not fully initialised even after the “Map” scene is initialised. Try inspecting those Managers at different stages of loading using MelonLoader.OnSceneWasLoaded (and filtering by scene name) in MelonLoader. As to whether it’s a good idea to extend things, my general principle is to use Melon when I can, and Harmony only when I need to. Then it’s to get my code called as early and as rarely as possible. Once on loading is best, once after GameObjects are initialised is fine (the Awake unity method), every time an attribute is pulled is worse, and every frame a last resort. Needless to say, changing functionality will be different than changing data.

If you prefer learning from examples, you can download any mod and “decompile” it using VS or dnSpy and see how they work. Sadly this erases comments, and replaces limited scope variable names with default ones, which can make code tricky to read. I did comment some of my earlier mods extensively while I was figuring out what was going on, so here’s the source if it helps you (please don’t judge it too harshly).

Examples.zip (7.8 KB)

I used MelonLoader.OnSceneWasInitialized as my way in. This way I could modify the game data after it’s been loaded into memory, but before the save file (or new map) is processed. To actually get the data I sometimes GlobalAssets and sometimes Unity’s Resources.FindObjectsOfTypeAll(typeof(_)) to search for all GameObjects of a particular class. The manager classes are also very useful (start with the singleton GameManager and follow the attributes chain) to get to elements that are specific to an ongoing game (rather than the fixed data). When I need to do more than that, ie, modify the UI, or the actual logic of the game, I use HarmonyPatch. Lastly, I’ve included a utils file that has helper function that simplifies C#'s reflection, very useful because HarmonyPatch extends methods from the “outside” so I’m constantly having to access protected or private fields.

Sorry for the overwhelmingly verbose wall of text, I tried to not assume too much prior knowledge; hopefully this answers your questions. And those of any lurkers that are too shy to ask.

2 Likes

Awesome! Thank you for the in-depth response.

Yes, I read through the Getting Started guide. I was still confused on how to work with the game objects. The task I’m trying to do is access settlement resource quotas for items, and I kept running into null object ref errors (classic) when trying to access things like the GameManager or ResourceManager. I thought I was accessing those managers incorrectly. I think I need to explore more accessing data via the scene callbacks methods.

What are you trying to do with them?

If you want, eg, to access or modify the production quotas as soon as ResourceManager is active you could use HarmonyPatch to Postfix ResourceManager.Awake(). The code would be something like

[HarmonyPatch(typeof(ResourceManager), "Awake")]
public class MyResourceManagerPatch
{
    public static void Postfix(ResourceManager __instance)
    {
        int logLimit = __instance.GetItemInfo("itemLogs").maxQuota;
        // Do whatever you wanted to do with this...
    }
}

I was trying to figure out when that Awake() method is called. I will look into HarmonyPatch.
The idea is a mod that sets settlement resource quotas automatically. I use settlement resource quotas to control overall production, and I want to automatically set that so I don’t have to enter all those quotas with each new settlement. It should be simple enough to set the default values in a file, then apply them to the quotas on map load. Then, I also need to tie into game save so it will take the current, in-game values and save those to file. So settlement resource quotas can be applied across different settlements, and it uses existing UI to set the values.
I think this would be a simple usability mod to help get started with modding overall.

AFAIK, Awake and similar methods are called by the underlying Unity engine that FF uses, not by code we have access to. It’s all “under the hood”.

What you want to do seems feasible enough. MelonLoader comes with its own config file writer, so that part can be handled fairly easily (although I’ve never tried it myself). And then you can use HarmonyPatch to apply the limits to ResourceManager as soon as it’s awake. You might also be able to use MelonLoader.OnSceneWasInitialized to apply it once the scene Map is loaded, although you’ll have to double check that that isn’t too early.

1 Like

I’ve just seen there’s a mod on steam workshop now that does just what @earf was asking for. I’m guessing that you managed to get your mod to work then?