It… depends on what kind of mod it is as well as how their save file structure is built. I haven’t touched this update so all I can make are some educated guesses.
First, let’s start with serialization of computer data, especially with mods.
A horribly bad metaphor for serialization of modular data
You live in a house. Big house. Many furniture things. And windows, doors, that kind of stuff. Now, for the sake of this metaphor, you will need to move all your things out of the house because of a Poltergeist. However, you are quite a lazy person and some things are very fragile, so you will need to hire companies around the world to do it.
Each company does the following: They get into your house, write a sticky note in their language (for example German, French, Spaghetti) which basically means “IOU item at this place”. They place the note and carry/take the thing apart.
Now your house is empty and you decide to go on vacations. You come back a year later and see that the ghost has died of boredom. After giving it a proper burial in an Indian graveyard, you decide that you want your stuff back. So you call all the companies and say “Hey. You’ve got stuff for my house!”
Each company comes, takes a look at the sticky posts they understand, get the part from their warehouse and replace it.
Ideally, you end up with the same house you got before. In any other case, you don’t.
Now, in this example, each company represents a mod. Mods can read all serialized data (I assume after quickly browsing
_saved_variables I think it was called) but they can only really make sense of what they know (i.e. in their “language”).
If a mod is missing, the data will not be replaced - i.e. the entity knows “Well, I had a “Curse of the Pharaoh” entity attached to myself”, but nobody cares.about extra data (most likely).
Now we get into the beautiful world of case-by-case, which - again - is just guessing.
Case 1: resource file overrides
This is sound, models, graphics, pure data (like journal entries, but not entity data). Adding overrides for these or removing them should work fine. There might be some strange side-issues with collision boxes or similar (if they were cached/accessible, which is currently not the case), but assuming you have an almost-identical thing, it should work in any case. The engine is merely referencing to those things, i.e. it saves the path, not the resource itself. The engine’s virtual file system takes care of handling overrides.
Case 2: Scripts that modify behaviour
This would apply to most of my mods - different name generator, different landscape generator, add buffs, remove buffs, that kind of stuff. This will be a case-by-case too, but if coded properly, removing should work - adding might not if the script relied on some kind of “starting state”.
Case 3: Removal, addition and modification of entities, buffs, and other runtime-data-stuff
This is where it gets tricky. Assume that you had an override that changed something about an entity, or had a mixinto, or something like that. All entities that were already created had - I suppose! - copy of this data, not the plain data itself. So when the override/mixinto is gone, the old entities will still use the old data. New entities will use the current data.
If you add a new entity, everything should be OK. If you modify an entity, it may affect older ones in a negative way (as in, dead references, missing buffs, that sort of thing). Removing an entity completely will cause… problems.
How to handle missing or invalid references to things.
So assuming something did change, an entity, buff, data file, callback handler or whatever was removed and the current code wants to access it (because the old data told it to). There are… a few ways that this could be handled.
Ignore. This is a sort of Minecraft way, I think. Everything that can’t be assigned will be deleted. This is safe-ish, as it results in a somewhat playable state, but may have cascades where you end up with a lot deleted. Especially painful if it was a simple rename, and not a deletion per se.
Fail. Throw a big exception, back to the main menu and error screen. Your save is corrupted, for whatever reason, and cannot be loaded. This is the very safest way because it guarantees, in some way, that code and data are consistent.
Try. If there is some sort of meta-data, the code may repair old data. For example, mods have some sort of “update reference” callback, or a “update entity to current version” callback thing. This will greatly increase the necessary work for programmers, as they have to write routines that patch stuff from A to B. This can be annoying, up to impossible (as in, infeasible to do) for complex things that were rewritten.
Mods that are simply overwriting models, sounds, or graphics and touch no code are very likely to be interchangeable or can be made interchangeable rather easily.
Mods that touch code, or live in code, are horribly case-by-case. It will depend a lot on what the engine can offer, what mod authors are willing to do and what their mod does. A mod that solely lives on a few events to do things will be almost unnoticed in most cases, where a total conversion mod will break the game hard.
In addition, the more a mod saves, the more… problematic this change can become. Terrain was mentioned and that’s one of those things: If you save the terrain color in the save, then changing the mod won’t change the colors and a new mod won’t have an effect on that.
If you re-choose the color upon loading, you get the proper color for the activated mods. However, this can also increase loading times…
The menu will likely become a third, independent lua state. Mods would not be loaded at this point - but rather become loaded as soon as the game itself is loading. That’s the way GMod is doing it, at least, and it’s pretty reasonable.
Every time you start a game you create a new lua state, load the mods, and run it. As soon as you quit the current game, the lua state is destroyed - and all mods neatly unloaded.