Page 1 of 1

Migrations on mod compatibilities

Posted: Fri Dec 29, 2023 8:18 pm
by DiegoPro77
Hi guys, I have a question.
I'm currently working on my ore refining mod: as the name says it introduces ore refining chains.

I was trying to add compatibility with Brevven's Lead mod, and I got a problem with migration files.
Let's say that smo is playing both mods, and I release this updated version that adds compatibility. Migrations will unlock the right recipes as long as the player has researched the right technologies, as migration files normally do.
But if smo doesn't run the Lead mod the game crashes since the items (lead intermediates) are not found, since the mod loads everything only if the mod is enabled in the game.

How can I fix this problem?
(Some of the recipe names are "lead-dust0", "lead-clump1", lead-chunk1" if you wanted to know them.)

Re: Migrations on mod compatibilities

Posted: Fri Dec 29, 2023 11:20 pm
by Deadlock989
As far as I know I don't think this is possible with JSON migration files. But you can write Lua migration files as well, and you can conditionally run a code block if and only if a specific mod is present (game.active_mods), or test for the existence of named prototypes, etc.

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 9:52 am
by DiegoPro77
Deadlock989 wrote: Fri Dec 29, 2023 11:20 pm As far as I know I don't think this is possible with JSON migration files. But you can write Lua migration files as well, and you can conditionally run a code block if and only if a specific mod is present (game.active_mods), or test for the existence of named prototypes, etc.
Oh interesting thing to know thank you (My knowledge about coding stopped active development in high school unfortunately :.) - and I was programming in Ruby, so pardon my ignorance on Api, events and on functions).
Regarding Lua migrations, this is what I wrote on the migration file: (ev-refining_2.1.0.lua)

Code: Select all

if mods ["bzlead"] then
  for index, force in pairs(game.forces) do
    local technologies = force.technologies
    local recipes = force.recipes
  
    if technologies["advanced-material-processing"].researched then
      recipes["lead-dust0"].enabled = true
    end
  end
end
But once I tried to load the game (Ev Refining enabled, Lead disabled) it gave me this error:

Code: Select all

Error while applying migration: Extended Vanilla: Refining: ev-refining_2.1.0.lua

__ev-refining__/migrations/ev-refining_2.1.0.lua:1: attempt to index global 'mods' (a nil value)
stack traceback:

__ev-refining__/migrations/ev-refining_2.1.0.lua:1: in main chunk
And what do you mean by "test the existence" of a prototype?

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 10:10 am
by DiegoPro77
Deadlock989 wrote: Fri Dec 29, 2023 11:20 pm As far as I know I don't think this is possible with JSON migration files. But you can write Lua migration files as well, and you can conditionally run a code block if and only if a specific mod is present (game.active_mods), or test for the existence of named prototypes, etc.
Wait I found out a piece of code that works and applies the migrations correctly by looking at your first link: (another time, thank you)

Code: Select all

for name in pairs(script.active_mods) do
  if name == "bzlead" then
    for index, force in pairs(game.forces) do
      local technologies = force.technologies
      local recipes = force.recipes
    
      if technologies["advanced-material-processing"].researched then
        recipes["lead-dust0"].enabled = true
      end
    end
  end
end
But the thing that I'm realizing now is: migration files as said here are applied only once and the game knows which files were already applied and which not.
But these technology unlocks should be checked every time my mod is put together with Lead.

I mean, am I sure that these unlocks will be always applied correctly without having to copy paste the migration file for each new version of the mod?

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 10:41 am
by Qon
DiegoPro77 wrote: Sat Dec 30, 2023 10:10 am But the thing that I'm realizing now is: migration files as said here are applied only once and the game knows which files were already applied and which not.
But these technology unlocks should be checked every time my mod is put together with Lead.

I mean, am I sure that these unlocks will be always applied correctly without having to copy paste the migration file for each new version of the mod?
You don't have to copy paste the migration file, because which recipes are unlocked is a part of the game state, saved in the savefile. Once unlocked, always unlocked.

If the mod author of lead recipes adds new recipes in a future mod update, which you also want to unlock with a different technology than their mod specified then you would need an additional migration for that (instead of modifying the already existing migration to include the new prototypes, which would not work for users updating from a version with the old migration).

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 12:01 pm
by Deadlock989
DiegoPro77 wrote: Sat Dec 30, 2023 9:52 am And what do you mean by "test the existence" of a prototype?
e.g.

Code: Select all

if game.recipe_prototypes["lead-dust0"] then
	-- do something
end
DiegoPro77 wrote: Sat Dec 30, 2023 10:10 am Wait I found out a piece of code that works and applies the migrations correctly by looking at your first link: (another time, thank you)
You don't have to loop through every active mod, you can do this:

Code: Select all

if game.active_mods["bzlead"] and game.recipe_prototypes["lead-dust0"] then
	for _,force in pairs(game.forces) do
		force.recipes["lead-dust0"].enabled = force.technologies["advanced-material-processing"].researched
	end
end
DiegoPro77 wrote: Sat Dec 30, 2023 10:10 am But the thing that I'm realizing now is: migration files as said here are applied only once and the game knows which files were already applied and which not.
But these technology unlocks should be checked every time my mod is put together with Lead.

I mean, am I sure that these unlocks will be always applied correctly without having to copy paste the migration file for each new version of the mod?
This kind of thing is what the on_configuration_changed event is for. This event fires when a saved game is loaded and any mod has changed version (including adding a mod to an existing save that didn't have it before). This would need you to get to grips with control.lua scripting, setting up event handlers and so forth.

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 2:07 pm
by DiegoPro77
Qon wrote: Sat Dec 30, 2023 10:41 am You don't have to copy paste the migration file, because which recipes are unlocked is a part of the game state, saved in the savefile. Once unlocked, always unlocked.

If the mod author of lead recipes adds new recipes in a future mod update, which you also want to unlock with a different technology than their mod specified then you would need an additional migration for that (instead of modifying the already existing migration to include the new prototypes, which would not work for users updating from a version with the old migration).
Yeah it makes sense and, at a certain degree I knew that. The thing was more about what Deadlock said in the last reply, and to work around that thing I should try to study how control.lua files work in a first place.
Deadlock989 wrote: Sat Dec 30, 2023 12:01 pm This kind of thing is what the on_configuration_changed event is for. This event fires when a saved game is loaded and any mod has changed version (including adding a mod to an existing save that didn't have it before). This would need you to get to grips with control.lua scripting, setting up event handlers and so forth.
It really would be interesting, and useful probably, but is it really worth it for me to go this far for now?
Now that you made me think about that, let me explain:
- A player downloads both mods and starts a new run: simplest case;
- A player playing Lead in a world decides to introduce Ev Refining: migrations aren't needed here too because all technologies need to be researched;

- A player playing Ev Refining decides to introduce Lead: migrations should apply thanks to the "if game.active_mods["bzlead"]"; (I'm right on this point am I?)


The only case where we have a problem is the one where a player:
-> Plays both mods -> Updates Ev Refining -> Deletes Lead -> Enables Lead

And well I dunno why someone would do something like that. (It would compromise the entire run.)
Deadlock989 wrote: Sat Dec 30, 2023 12:01 pm You don't have to loop through every active mod, you can do this:
Yeah I tend to overdo sometimes while coding, thank you. xD

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 2:48 pm
by Deadlock989
DiegoPro77 wrote: Sat Dec 30, 2023 2:07 pm The only case where we have a problem is the one where a player:
-> Plays both mods -> Updates Ev Refining -> Deletes Lead -> Enables Lead

And well I dunno why someone would do something like that. (It would compromise the entire run.)
If a player can break something, at least one will. Whether it's worth handling or not it is a subjective judgement for you. There are some mods which simply aren't ever going to work out well when introduced or removed mid-game. In that case it may be massively less work for you to simply warn the punters about that.

For mods which add only brand new recipes to brand new technologies, in general I don't feel any need to worry - the save game state keeps track of it all and if a player removes and then reinstalls the mod, there's not a great deal you can do about that.

But if you add a new recipe to a vanilla technology or arguably a technology provided by a third party mod, players are going to expect to have access to it if they already researched that technology and they add your mod later. For example this mod has a very simple on_configuration_changed script that checks to see if Optics research has already been completed and updates one specific recipe's availability, whenever the mod is added or updated.

There is also the option of using force.reset_technology_effects() - I sometimes use this for when tricksy mod combos change and just wholesale updating every recipe availability at once. For example IR3 does this when Dectorio is added or removed.

Re: Migrations on mod compatibilities

Posted: Sat Dec 30, 2023 5:25 pm
by Qon
DiegoPro77 wrote: Sat Dec 30, 2023 2:07 pm Yeah it makes sense and, at a certain degree I knew that. The thing was more about what Deadlock said in the last reply, and to work around that thing I should try to study how control.lua files work in a first place.
I'm sorry, I focused on the "don't copy migrations each update part" didn't have time before to tell you about on_configuration_changed.
migration scripts are basically just for your own mods internal changes that need to be migrated. Inter-mod configuration and interaction changes is what on_configuration_changed is for. Use that. It's not hard or a lot to learn, you just name the file control.lua (directly in the mod folder, not in a sub folder) and put the code in the event handler (not technically an event like the others, so different syntax).
all you need is your idempotent (it already is so don't worry) migration in the control.lua inside the event handler

Code: Select all

script.on_configuration_changed(function(event)
	if game.active_mods["bzlead"] and game.recipe_prototypes["lead-dust0"] then
		for _,force in pairs(game.forces) do
			force.recipes["lead-dust0"].enabled = force.technologies["advanced-material-processing"].researched
		end
	end
end)
https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#on_configuration_changed wrote:Register a function to be run when mod configuration changes. This is called when the game version or any mod version changed, when any mod was added or removed, when a startup setting has changed, when any prototypes have been added or removed, or when a migration was applied. It allows the mod to make any changes it deems appropriate to both the data structures in its global table or to the game state through LuaGameScript.
DiegoPro77 wrote: Sat Dec 30, 2023 2:07 pm
Deadlock989 wrote: Sat Dec 30, 2023 12:01 pm This kind of thing is what the on_configuration_changed event is for. This event fires when a saved game is loaded and any mod has changed version (including adding a mod to an existing save that didn't have it before). This would need you to get to grips with control.lua scripting, setting up event handlers and so forth.
It really would be interesting, and useful probably, but is it really worth it for me to go this far for now?
It's not "going far", it's quick, easy and CORRECT. Why do it incorrectly when it's just as easy to do it correctly and avoid all the bugs, no matter what chain of removal and adding of mods you come up with.
DiegoPro77 wrote: Sat Dec 30, 2023 2:07 pm And well I dunno why someone would do something like that. (It would compromise the entire run.)
Maybe someone adds the mod, tries removing it to debug which mod is causing some bug, before crafting much of anything from the mods. Then adds the mods back in again. Now suddenly the recipes that worked before are now just gone! But since you have now decided to not write bugs on purpose and put the code in control.lua in the on_configuration_change handler you don't have to worry about this :)

Re: Migrations on mod compatibilities

Posted: Wed Jan 03, 2024 9:53 am
by DiegoPro77
Deadlock989 wrote: Sat Dec 30, 2023 2:48 pm If a player can break something, at least one will. Whether it's worth handling or not it is a subjective judgement for you. There are some mods which simply aren't ever going to work out well when introduced or removed mid-game. In that case it may be massively less work for you to simply warn the punters about that.
Definitively true.
Deadlock989 wrote: Sat Dec 30, 2023 2:48 pm For mods which add only brand new recipes to brand new technologies, in general I don't feel any need to worry - the save game state keeps track of it all and if a player removes and then reinstalls the mod, there's not a great deal you can do about that.
Yeah, but I must say that Qon is right on this fact:
Qon wrote: Sat Dec 30, 2023 5:25 pm Maybe someone adds the mod, tries removing it to debug which mod is causing some bug, before crafting much of anything from the mods. Then adds the mods back in again. Now suddenly the recipes that worked before are now just gone! But since you have now decided to not write bugs on purpose and put the code in control.lua in the on_configuration_change handler you don't have to worry about this :)
And it can become handy since my mods are not big enough to stand alone: everyone here always asks for compatibilities, and compatibilities, and compatibilities, and so on...
I even started to play some of these mods players continue to talk me about just to see how to balance things out. (and have some fun and not just modding xD)
I'll probably add compatibility with IR3 too if it adds new minerals. (There are so many mods wow)
Qon wrote: Sat Dec 30, 2023 5:25 pm Inter-mod configuration and interaction changes is what on_configuration_changed is for. Use that. It's not hard or a lot to learn, you just name the file control.lua (directly in the mod folder, not in a sub folder) and put the code in the event handler (not technically an event like the others, so different syntax).
all you need is your idempotent (it already is so don't worry) migration in the control.lua inside the event handler

Code: Select all

script.on_configuration_changed(function(event)
	if game.active_mods["bzlead"] and game.recipe_prototypes["lead-dust0"] then
		for _,force in pairs(game.forces) do
			force.recipes["lead-dust0"].enabled = force.technologies["advanced-material-processing"].researched
		end
	end
end)
I'll try to learn these control scripts then if this is their job to fix these problems. xD
Deadlock989 wrote: Sat Dec 30, 2023 2:48 pm But if you add a new recipe to a vanilla technology or arguably a technology provided by a third party mod, players are going to expect to have access to it if they already researched that technology and they add your mod later. For example this mod has a very simple on_configuration_changed script that checks to see if Optics research has already been completed and updates one specific recipe's availability, whenever the mod is added or updated.
Will keep an eye on that, it seems interesting.
Deadlock989 wrote: Sat Dec 30, 2023 2:48 pm There is also the option of using force.reset_technology_effects() - I sometimes use this for when tricksy mod combos change and just wholesale updating every recipe availability at once. For example IR3 does this when Dectorio is added or removed.
Also interesting, if smth is wrong I'll repost here, thank you guys for the helps. <3