Jump to content

Recommended Posts

Posted

I play around with a lot of mod at times.. and one thing got my attention..

The mod load order.. could really use a feature like that.. just thought it was worth mentioning..

Posted (edited)

There is such a thing. Dependencies. It doesn't seem well fleshed out yet, as "soft" dependencies throw a crapton of warning messages on startup,

But if you want your mod to load last, give it a dependency on some mod you use that has a dependency on another mod. Something like Expanded Foods. Then name your mod something like "ZZZerrificFunMod" Recurse the chain as long as you need to make sure everything else loads first.

Edited by Thorfinn
  • 9 months later...
Posted (edited)
On 3/27/2025 at 11:22 AM, Thorfinn said:

There is such a thing. Dependencies. It doesn't seem well fleshed out yet, as "soft" dependencies throw a crapton of warning messages on startup,

But if you want your mod to load last, give it a dependency on some mod you use that has a dependency on another mod. Something like Expanded Foods. Then name your mod something like "ZZZerrificFunMod" Recurse the chain as long as you need to make sure everything else loads first.

@ThorfinnCould you help me with this scenario. I have butchering and r.meat installed. both change the drops for animals when vanilla harvesting, in opposite directions. r.meat also changes what you get out of the butchering table. it seems whatever patch to the vanilla drops r.meat applies is what takes effect, which makes butchering practically irrelevant. how would i theoretically get butchering's patches to take effect on the vanilla item drops over r.meat? would making butchering dependent on r.meat make it override r.meats patches?

Edited by IAmMoss
forgot to tag person im responding to
Posted

an ideal solution would be to traverse the mods first, and build the dependancy map, before the actual loading of the mods. that way the game builds up the list of mods to load, scans for dependancies, reorders them according to what needs to be loaded first before anything else, and then proceeds to do the loading of the mods in the proper order.

  • Like 1
Posted

I think in this case I'd brute force it, @IAmMoss. Just open up the butchering mod and edit its dependencies to include r.meat, so it forces that to load first. Without looking at the dependencies in each of those, I'm not sure how you could force butchering to be a later load order using your own mods. There may be a more elegant solution, but going in blind, I don't know.

 

Posted
On 1/7/2026 at 11:44 AM, Dilan Rona said:

an ideal solution would be to traverse the mods first, and build the dependancy map, before the actual loading of the mods. that way the game builds up the list of mods to load, scans for dependancies, reorders them according to what needs to be loaded first before anything else, and then proceeds to do the loading of the mods in the proper order.

Pretty sure that's how it works now. It goes through all mods and loads all the ones with no dependencies first. Then it goes through the list of unloaded mods to see if any of those dependencies are now met, and loads that tranche. Repeat until everything is loaded.

  • 2 weeks later...
  • 1 month later...
Posted (edited)
On 1/9/2026 at 6:37 AM, Thorfinn said:

Pretty sure that's how it works now. It goes through all mods and loads all the ones with no dependencies first. Then it goes through the list of unloaded mods to see if any of those dependencies are now met, and loads that tranche. Repeat until everything is loaded.

Where is the source code for this?  I'm growing a bit tired of people throwing out "it probably does this" without looking at what the game code actually does.  I strongly suspect that VS is subject to on-disk inode ordering, or in-memory hash ordering (which varies) -- at least for mods which lack dependencies.  I am not convinced the mods are loaded in alphabetically-sorted order (and it's very possible that order would vary depending on user's locale).  I have recent proof of my theory as well.

On ModDB site, we see time and time again reports of misbehaviour in various mods due to module loading order.  We have people doing silly things like adding a variable number of "z"s to the start of their mod names.  This needs to stop.  In the UNIX world (for boot-up script ordering and for package dependency ordering) we have solved this problem in various ways, so to see it happen in a game is disheartening.

Yes, explicit dependencies called out via "dependencies" modinfo.json attribute will get loaded first/in order.  But that doesn't answer the whole question, does it?  Example: mod A and mod B both have an explicit dependency on mods C and D.  Which mod gets seen first: A or B?  And which mod gets loaded first: C or D?  Don't answer quickly -- really think about this before answering.  Remember: modinfo.json "dependencies" attribute is not a list/array, it's a dict/hash/map.

Now think about modules without any "dependencies" reliance (as a dependency, or dependent on other things).  What order do those get loaded in?

So, please point me to the VS source code where module loading happens.  I can reverse-engineer from there what is going on.  It's about time we get proper answers.

Edited by tsuchinoko
Posted (edited)
4 hours ago, tsuchinoko said:

Where is the source code for this?  I'm growing a bit tired of people throwing out "it probably does this" without looking at what the game code actually does. 

...

So, please point me to the VS source code where module loading happens.  I can reverse-engineer from there what is going on.  It's about time we get proper answers.

I'm just going by what the log files say the load order is. It's reporting alphabetical order of things that have no dependencies, etc. Who knows, it may well be lying to us. Probably it's plotting with the communists to overthrow everything good and wholesome in the world.

The link to all the source code is in the modding section on the official wiki.

You have a heck of a way to say, "Hi!"

Edited by Thorfinn
Posted
29 minutes ago, Thorfinn said:

I'm just going by what the log files say the load order is. It's reporting alphabetical order of things that have no dependencies, etc. Who knows, it may well be lying to us. Probably it's plotting with the communists to overthrow everything good and wholesome in the world.

The link to all the source code is in the modding section on the official wiki.

You have a heck of a way to say, "Hi!"

Thanks, I'll start digging through wiki!

So the questions I posed (re: mod A vs. B, and C vs. D) are still unknown. I refute the claim it's alphabetical; if it was alphabetical, things like https://mods.vintagestory.at/translocatorlocatorredux#cmt-137964 couldn't happen.

What should happen in that linked case: configlib (CL) loads, depends on vsimgui (ImGui) per modinfo.json "dependencies" attribute, vsimgui loads, configlib finishes loading, translocatorlocatorredux (TLLR) loads sometime later, all is great.  The only way this bug could happen is if TLLR loaded before CL, which would cause its runtime check for CL to fail (acting as if CL wasn't available).  "c" comes before "t" in both ASCII and UTF-8 sorting order.  CL has dependencies as well.  I think you now understand why I asked about the A/B and C/D issue. 🙂

My way of saying "hi" is: reverse engineering, fixing bugs, addressing shortcomings.  Considering this has been a repeated problem for probably 9 years -- ChangeLog says mods got introduced in 1.0.10 / November 2016 -- it's clear devs have higher priorities (that's fine!).  So rather than whinge, I figure I might as well do something about it.  (Warning: old assembly and C programmer since the late 80s.)

Posted (edited)

Dug into this as promised.  The source code for this is not available.  vsapi repo does not contain the actual code.  For whatever reason this code is closed-source.  Here's the nitty gritty per JetBrains' dotPeek:

VintagestoryLib.dll is what contains the actual code.  Within this, there is a namespace called Vintagestory.Common, which contains class ModLoader.  This ModLoader class contains many functions that are not documented anywhere, while others (naturally) are what you see in Vintagestory.API.Common (probably exported or at least documented; not sure if the whole class itself is exported/inherited or not).  The main function that does the "heavy lifting" seems to be LoadMods() and Unpack().

Unpack() is the ZIP handler/unpacker portion, which ends up creating the stuff you see under Cache/unpack.  I suspect this directory structure is then iterated over when loading mods (making a big assumption but it seems logical).

The LoadMods() function references a new class called ModContainer (also part of Vintagestory.Common).  It is here that we find actual code that iterates over directory contents when given a path and so on, particularly in function EnumerateModFiles:

public static IEnumerable<string> EnumerateModFiles(string path)
  {
    IEnumerable<string> first = Directory.EnumerateFiles(path);
    foreach (string enumerateDirectory in Directory.EnumerateDirectories(path))
    {
      if (!(Path.GetFileName(enumerateDirectory) == ".git"))
        first = first.Concat<string>(ModContainer.EnumerateModFiles(enumerateDirectory));
    }
    return first;
  }

The Directory is, of course, a native NET class.  EnumerateDirectories is defined here: https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratedirectories?view=net-8.0 .  These results are not returned in any particular order; programmers are expected to sort/order results using other methods/functions, most commonly the NET Order* methods.

Searching the entire decompiled ModContainer class (and its functions), as well as ModLoader class (and its functions) for the term "Order" -- which is a submethod prefix for sorting/ordering iterable results -- turns up nothing.  The same for the word "Sort".

Now switching gears to Vintagestory.Common.API -- the open-source one -- class ModInfo.  This code hasn't been touched in roughly 8 years.  But we find this cute thing:

        /// <summary>
        /// If you need mods to be executed in a certain order, adjust this methods return value.<br/>
        /// The server will call each Mods StartPre() and Start() methods in ascending order of each mods execute order value. And thus, as long as every mod registers it's event handlers in the Start() method, all event handlers will be called in the same execution order.<br/>
        /// Default execute order of some survival mod parts<br/>
        /// Worldgen:<br/>
        /// - GenTerra: 0 <br/>
        /// - RockStrata: 0.1<br/>
        /// - Deposits: 0.2<br/>
        /// - Caves: 0.3<br/>
        /// - Blocklayers: 0.4<br/>
        /// AssetsLoaded event<br/>
        /// - JsonPatch loader: 0.05<br/>
        /// - Load hardcoded mantle block: 0.1<br/>
        /// - Block and Item Loader: 0.2<br/>
        /// - Recipes (Smithing, Knapping, Clayforming, Grid recipes, Alloys) Loader: 1<br/>
        /// </summary>
        /// <returns></returns>
        public virtual double ExecuteOrder()
        {
            return 0.1;
        }

I do not know the full impact of the above yet -- unsure if applies to only built-in DLL/code mods, or if it can apply to public mods as well.  I suspect all mods have StartPre/Start functions but I suspect the order might be pre-determined by the mod builder template code that everyone uses to build their mods.  It's certainly not exposed via modinfo.json.

I still have a lot more reverse engineering to do on this, as I certainly believe the claim that (in the logs) mods are being listed in alphabetically-sorted order, but everything I am seeing so far in both open-source portions and decompiled portions implies there is no sorting -- which means susceptible to 1) in-memory hashing, and 2) disk inode order.  If something is sorting results somewhere, OK, but I need to determine how/where.

Oh what I'd give to be back in the days of SoftICE where I could debug this in real-time.  On the flip side, I'm really glad that the VS folks include PDB files with everything, which makes this a bit easier.  ❤️

Edited by tsuchinoko
Posted

Very interesting. So if they use the same criteria for loading external mods, they must do an initial pass to find all those with TerraGen characteristics, load those, then the JSON patch loaders, repeat until you get to mods which have only recipes?

That could well be. Pretty sure that for testing purposes, I was using no mods at all that affected worldgen. Thinking about it, I think they all were JSON patches. Even my own personal mod that had a few extra blocks also had JSON patches, so everything would have been the same priority. One quick way to test, I suppose, would be to create a mod pair, one that creates a new block, one that adds a recipe for that block.

Maybe that's why Expanded Foods was split up the way it was?

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.