Lifecycle, callbacks, and inter-mod communication

Place to get help with not working mods / modding interface.
Post Reply
danielbrauer
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu May 18, 2017 2:22 pm
Contact:

Lifecycle, callbacks, and inter-mod communication

Post by danielbrauer »

Suppose I have two mods: Service and Client. Both mods work on their own, but Client needs to register something with Service if both are present. So:
  • Client declares a dependency on Service so that its callbacks come after.
  • Client implements on_init() and uses a remote API to register with Service.
This works fine if both mods are present when the game starts, but what if Client is only introduced later in play?
  • When the save is loaded, on_init gets called for the Client.
  • (Note that because on_init is only called once per mod lifetime per game, it is not called for Service)
  • Client sees Service is present in on_init, and calls the registration function through the remote API.
The problem here is that Service hasn't had a chance to wake up yet. No on_init (already happened in this save), no on_load (still to happen), meaning its global data isn't linked yet. The only solution I've got at the moment is to have an API which is designed to be called in on_init and on_configuration_changed. If it gets called in on_init and global data isn't linked yet, we assume it's about to be called in on_configuration_changed (after on_load).

This all seems awkward and convoluted. It feels like on_init shouldn't be used for inter-mod communication because of the above situation, and instead that on_configuration_changed should be called after a new game is started. This way on_init/on_load can be for internal stuff, and anything that depends on their setup can wait until on_configuration_changed.

Or am I missing something?

User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3699
Joined: Tue May 13, 2014 11:06 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by DaveMcW »

danielbrauer wrote:
Sun Feb 23, 2020 12:16 pm
Or am I missing something?
You should have access to everything in on_init().

danielbrauer
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu May 18, 2017 2:22 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by danielbrauer »

Right, but in the above scenario, when the Client mod calls the Service API in on_init, the Service mod will not have its local references to the global table yet.

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by eradicator »

danielbrauer wrote:
Sun Feb 23, 2020 2:04 pm
Right, but in the above scenario, when the Client mod calls the Service API in on_init, the Service mod will not have its local references to the global table yet.
Then create them when the client calls. Personally i use the on_init_config approach where i don't distunguish between the two anymore. It's a bit slower, but less bothersome.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.

danielbrauer
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu May 18, 2017 2:22 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by danielbrauer »

eradicator wrote:
Sun Feb 23, 2020 4:50 pm
Then create them when the client calls.
It definitely feels like there's a problem with the lifecycle logic if I have to guard against uninitialised local variables. Shouldn't that be the whole point of on_load?
Personally i use the on_init_config approach where i don't distunguish between the two anymore. It's a bit slower, but less bothersome.
Can you point me to more information about this approach? There are no Google hits for "on_init_config factorio"

User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3699
Joined: Tue May 13, 2014 11:06 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by DaveMcW »

danielbrauer wrote:
Mon Feb 24, 2020 2:49 pm
It definitely feels like there's a problem with the lifecycle logic if I have to guard against uninitialised local variables. Shouldn't that be the whole point of on_load?
No, on_load has a very unfortunate name.

There are 3 main uses for on_load:
1. Confusing new modders
2. Breaking multiplayer
3. Doing these specific things: https://lua-api.factorio.com/latest/Lua ... ap.on_load

User avatar
Oktokolo
Filter Inserter
Filter Inserter
Posts: 883
Joined: Wed Jul 12, 2017 5:45 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by Oktokolo »

Just because nobody linked it yet: Data Lifecycle
global is writable in on_configuration_changed - wich is the latest of the mod "initialization" events. So if you want to write to global before the player may trigger any events, you have to do it there.
If that does not suffice, there is always the possibility to do it in on_nth_tick (looks like you can even unregister the handler when the work is done).

danielbrauer
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu May 18, 2017 2:22 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by danielbrauer »

I'm disappointed that this appears to be a hole in the API, but I've solved my problem by having my remote functions call on_load to link global tables if they haven't been linked yet.

Thanks everyone for your help!

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by eradicator »

danielbrauer wrote:
Mon Feb 24, 2020 2:49 pm
It definitely feels like there's a problem with the lifecycle logic
Sure does. But it's what we got.
danielbrauer wrote:
Mon Feb 24, 2020 2:49 pm
Can you point me to more information about this approach? There are no Google hits for "on_init_config factorio"
That's just what i call my "dual use" function that i bind to both events. I.e. a function that is built in a way that it doesn't matter if it's called in on_init or on_config.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.

danielbrauer
Long Handed Inserter
Long Handed Inserter
Posts: 93
Joined: Thu May 18, 2017 2:22 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by danielbrauer »

eradicator wrote:
Sat Feb 29, 2020 9:43 pm
danielbrauer wrote:
Mon Feb 24, 2020 2:49 pm
It definitely feels like there's a problem with the lifecycle logic
Sure does. But it's what we got.
I would go so far as to say that this is a design bug, and Wube should consider addressing it before 1.0. I think the solution is as simple as calling on_configuration_changed after on_init for new games, so that mods always have a safe place to talk to other mods on startup. The current situation requires all sorts of custom code to make sure things are safe, and it's really not Ok that this responsibility is pushed to the mod developer.

User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5206
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by eradicator »

They're not gonna change anything that has the potential to break a large amount of mods at this point.
Author of: Belt Planner, Hand Crank Generator, Screenshot Maker, /sudo and more.
Mod support languages: 日本語, Deutsch, English
My code in the post above is dedicated to the public domain under CC0.

User avatar
Oktokolo
Filter Inserter
Filter Inserter
Posts: 883
Joined: Wed Jul 12, 2017 5:45 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by Oktokolo »

eradicator wrote:
Fri Mar 06, 2020 5:21 pm
They're not gonna change anything that has the potential to break a large amount of mods at this point.
The overwhelming majority of mods is simple enough to not need any of that initialization events. So such a change has not the potential to break a large amount of mods.
On the other hand, Bob's has been broken by engine-changes multiple times. So the potential of breking the most-used mods isn't an obstacle either.
Also, most mods probably do not even exist yet as they will be written by future players wich come to the game after release of 1.0.0.

I would expect the devs feeling quite comfortable changing the init events - if they deem such a change to be beneficial enough to mod writers.
Sadly, the very point of not much mods beeing affected by that events is also a point against changing the initialization events. Every change costs dev time and comes with the potential of introducing new bugs after all...

Rseding91
Factorio Staff
Factorio Staff
Posts: 13171
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by Rseding91 »

Mod <> mod communication has always been a pain point because of one simple thing:

You can never guarantee that mod B is ready for mod A to call it.

Because:

Mod A runs before mod B and in mod A on_init mod B has not run yet but mod A tires to call mod B.

And so the entire thing is just doomed to have special checks. There's nothing I can do about that.
If you want to get ahold of me I'm almost always on Discord.

Hornwitser
Fast Inserter
Fast Inserter
Posts: 204
Joined: Fri Oct 05, 2018 4:34 pm
Contact:

Re: Lifecycle, callbacks, and inter-mod communication

Post by Hornwitser »

Rseding91 wrote:
Mon Mar 09, 2020 11:54 am
You can never guarantee that mod B is ready for mod A to call it.
Isn't this the whole point of the dependency declaration in info.json? mod-a says it depends on mod-b, and that ensures that mod-b is invoked before mod-a, and this works as expected when both mods are installed at the same time. Maybe a diagram is order for describing what's going on here. Assuming mod-a says it depends on mod-b:

Code: Select all

New game with mod-a and mod-b installed:
mod-a     mod-b
  .         .
  .       on_init
  .         |
on_init     |
  |         |

New game started with just mod-b installed:
mod-a     mod-b
  .         .
  .      on_init
  .         |

Restart installing mod-a:
mod-a     mod-b
  .         .
on_init     . <- mod-b is uninitialized!
  |         .
  |       on_load
  |         |
  |       on_cfg_chg
  |         |
on_cfg_chg  |
  |         |

Post Reply

Return to “Modding help”