On pre save request

Things that we aren't going to implement
Post Reply
Asynchron
Burner Inserter
Burner Inserter
Posts: 18
Joined: Fri Dec 02, 2022 9:10 pm
Contact:

On pre save request

Post by Asynchron »

Hi team,

I've noticed there is no pre_save event in factorio. Could it be added into the api?

This prevents any proper saving of information by a mod when player is trying to save.
If you have some info that is not yet saved in save table (forgot how it is called), then there is a chance that upon saving a game, some critical information could get lost.

Regards,
Asynchron.

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: On pre save request

Post by Deadlock989 »

Asynchron wrote:
Sun Dec 04, 2022 10:17 pm
If you have some info that is not yet saved in save table (forgot how it is called)
The global table.

Don't do that. If it's a variable, and it persists beyond an event, keep it in the global table, or you will desync every time someone connects in multiplayer.

https://wiki.factorio.com/Tutorial:Modd ... nd_desyncs
Image

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 2228
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: On pre save request

Post by boskid »

But why? Correctly implemented mod should keep all state data in `global` variable so it is ready to be saved literally in between of any event. A pre_save event would not be deterministic (could happen on one client while not happening on other clients) and as such if it would change game state it would desync (it is literally impossible to implement this in a deterministic way, because you can always record a replay and when playing the replay you can save in the middle of recording to resume playing from that state, and here a save would happen that was not previously seen in the replay).

I am moving this to won't implement because with current knowledge, there are no problems this event would solve that are not possible to solve by simply keeping state data inside of `global` at all times. There is an event on_load which is not deterministic but is required due to limitation of the save-load process, that event is already causing problems for various modders because handler for that event is supposed to get rid of all differences in the lua context that was introduced by save-load cycle: it should restore metatables (when not using registered metatables) so loaded objects are no different than on other players instances, it should re-setup conditional event handlers so they are the same as on other players, and it should restore local references (anything outside `global` that references object inside of `global`) so the script context is same as on other players. When a modder uses this event not to get rid of differences, but the opposite: to introduce a difference (setting a flag that will have a game state effect, maybe in next tick) it will desync. Our architecture of scripting is that we only ever expose game state data to script and we only raise events that are part of game state (on_load is unfortunately the only exception) so because pre_save cannot be guaranteed to be deterministic, it will never happen.

Asynchron
Burner Inserter
Burner Inserter
Posts: 18
Joined: Fri Dec 02, 2022 9:10 pm
Contact:

Re: On pre save request

Post by Asynchron »

Well the thing with global table is that you have to do this restoration manually, which complicates things if you for example use typescript to lua compiler, as they add some logic to compiled ts classes to lua to make their behavior compatible, and basically would require you to mess with their runtime lib for that.

Another problem with global table approach is that if you have lambdas in your objects, well, to put it mildly, you can't expect them to live in that global table, and that prevents you from having objects with listeners, or even something as basic as promises.

I apologize if I'll say something wrong in next section, since I didn't play multiplayer in factorio, and neither was much around in forums.
In regards to desyncs and stuff, seems like on_load is a hack that pushes all desync stuff onto modders themselves to handle.

Upon logging into a multiplayer session, isn't it possible to just send mod/lua state to the game from another player?
If done this way, first player in the session would initialize all the required stuff, while subsequent players that joined would just get up to date lua state.

User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 2228
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: On pre save request

Post by boskid »

Asynchron wrote:
Mon Dec 05, 2022 10:19 am
Upon logging into a multiplayer session, isn't it possible to just send mod/lua state to the game from another player?
If done this way, first player in the session would initialize all the required stuff, while subsequent players that joined would just get up to date lua state.
Well, this is not how scripting save-load works right now. When saving we only save the `global` table and when loading the script context is repopulated from scratch (control.lua file is loaded and executed which may load other files, then `global` is populated using data from save file and the on_load handler is called to request script to fill all the gaps left by this save-load process). Lua does not provide us a way to save entire execution context and most likely we would never use that even if available because that would create new set of annoying challenges (how would a migration look like when mod's code is changed so a new control.lua would need to be loaded without loosing game state objects but in a way that temporary objects from old script would be removed) that right now can be elegantly solved with this one solution of only saving `global` variable and then raising on_load hook.

on_load is unavoidable necessity due to our saving solution but it is also quite simple to understand, flexible for allowing mods update and game engine updates and already well known. Whatever your technology is, right now it seems to be incompatible with our scripting support.

If you can show me one good use case for pre_save hook that would make some hard problem super easy or super fast i will discuss this and reconsider this topic. Without a good example there are no hopes because i have to weight the gains of adding pre_save hook with its consequences (how likely modders will use it incorrectly causing more hard to reproduce desyncs, blaming them on us). Without example this feature has pros of value 0 and a huge possibility of being an XY problem which can be solved differently but you are not showing what the real problem is.

Asynchron
Burner Inserter
Burner Inserter
Posts: 18
Joined: Fri Dec 02, 2022 9:10 pm
Contact:

Re: On pre save request

Post by Asynchron »

ok, at the moment I don't think I have an enough strong case for adding pre_save (I just don't try saving anymore) given the problems you've mentioned, but if there will be, I'll post it here.

In regards to transferring lua state, I didn't imply it to be used for saving files too (which would cause the migration issue you've mentioned), but only for sync between players in one multiplayer session, in which case versioning problem shouldn't even be there per my understanding. It's sad that lua doesn't allow that, and probably a simple serialization lib wouldn't cut as well.

curiosity
Filter Inserter
Filter Inserter
Posts: 316
Joined: Wed Sep 11, 2019 4:13 pm
Contact:

Re: On pre save request

Post by curiosity »

Some mods keep lots of temporary data out of global to reduce save size. What you suggest may drastically increase the amount of data to transfer on join.

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

Re: On pre save request

Post by Rseding91 »

curiosity wrote:
Wed Dec 07, 2022 3:55 am
Some mods keep lots of temporary data out of global to reduce save size. What you suggest may drastically increase the amount of data to transfer on join.
If the data is required to save/load then it's required and size is irrelevant since it is required to save/load. If it's not, it doesn't need to be in the global table.

EDIT: unless you meant 'saving the whole lua state'? In which case yes you would be correct; it would waste a lot of save size.
If you want to get ahold of me I'm almost always on Discord.

Post Reply

Return to “Won't implement”