Page 1 of 1
how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 3:10 am
by AntiElitz
So when I load a game with my mod, i want to check if some configurations in the config changed. So i registered an event for on_load to check if the config changed. However the on_load cannot edit global variables(cause they are not loaded yet). So i got a workaround here to make it update on the first tick instead.
Code: Select all
function events.on_load(event)
trigger_on_load = true
end
function events.on_tick()
if trigger_on_load then
init.initialize()
trigger_on_load = nil
end
end
function init.initialize()
step_check_config_changed()
end
This Code is working wonderfull in Singleplayer, but causes a instant desync in MP for joining players because the variable trigger_on_load is not global and therefor diffrent for each players. but i cannot define a global in on_load. So how am i supposed update the config-data when loading the game while keeping MP compatibility? THX for the help!
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 3:27 am
by Nexela
The correct way to do it is in on_configuration_changed or possibly via migration scripts in the migration folder
the dirtiest way would be to register and un-register a custom event in the tick handler (register in on_load and un_register after the tick handler has run) -- I do this for SP testing so I don't have to increment version and change folder names everywhere
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 3:43 am
by AntiElitz
on_configuration_changed does only fire on game or mod update, not on every load. What i actually want to check is if the user changed the options in my mod folders config file. This is not a mod update tho and does not get capture by on_configuration_changed.
Code: Select all
the dirtiest way would be to register and un-register a custom event in the tick handler (register in on_load and un_register after the tick handler has run) -- I do this for SP testing so I don't have to increment version and change folder names everywhere
Could you post an example of that? I get the idea but i don't fully understand without code i guess :/ . TX for your help!
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 4:22 am
by Nexela
Using stdlib events makes this easier

(if you are not using the tick handler you can just register on_tick and unregister on_tick inside of on_tick)
Also not 100% sure how this would work in MP
pseudo code below
Code: Select all
local my_event = script.generate_event_name()
script.on_load(function ()
script.on_event(my_event, function()
update code here
script.on_event(my_event, nil) --nil the event to remove it
end)
end)
script.on_event(defines.events.on_tick, function(event)
game.raise_event(my_event)
blah blah blah rest of your tick code here.
)
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 5:13 am
by Rseding91
If you do any of the things listed here it will desync when used in MP and or break replays in single player.
Just FYI.
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 5:23 am
by aubergine18
Rseding91 wrote:If you do any of the things listed here it will desync when used in MP and or break replays in single player.
Would it be worth the devs doing a few youtube vids or something explaining how multiplayer works and the differences between MP and SP, and explaining how the desych happens and how to avoid it?
For example, when I was looking through the EvoGUI code I noticed that things like using string format %f could cause desynch because different operating systems output slightly different results. And I saw in another mod that if you make a local reference to math.random that can cause problems too. Then there's all the config change stuff and proper comprehension of the events like on_init, on_load and on_configuration_changed.
It would be useful to have a resource that modders can look at to get a better understanding of how to write desynch-free code.
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 5:57 am
by Nexela
Rseding91 wrote:If you do any of the things listed here it will desync when used in MP and or break replays in single player.
Just FYI.
Nexela wrote:
Also not 100% sure how this would work in MP
Guess I can change that to being 100% sure it doesn't work in mp. But as I said it was only something I did for single player testing/devolping where desyncs and replay don't matter.
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 11:03 am
by Adil
AntiElite wrote:However the on_load cannot edit global variables(cause they are not loaded yet).
Where did that came from?
Modifying "global." is the sole purpose of on_load,(edited) It's game objects that are only a dead weight at this stage.
The desync comes from "trigger_on_load = true ". This line defines local variable, when second player connects, onload is fired only for him, so other players don't have the same variable, and on next tick it is polled for its value.
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 12:20 pm
by AntiElitz
Adil wrote:AntiElite wrote:However the on_load cannot edit global variables(cause they are not loaded yet).
Where did that came from?
Modifying "global." is the sole purpose of on_load, It's game objects that are only a dead weight at this stage.
The desync comes from "trigger_on_load = true ". This line defines local variable, when second player connects, onload is fired only for him, so other players don't have the same variable, and on next tick it is polled for its value.
If I use global here, it tells me its not possible in on_load
Code: Select all
function events.on_load(event)
global.triggerinitialize = true
end
Error while running mod-UPS++::on_load().
Detected modifications to the 'global' table:
CRC before: 1095740016
CRC after: 2444180806
I just want to run a function the tick after loading a game ... not after a player joining ... not before the entitys are loaded ... and without any desync - I've never thought this is gonna be so difficult
Rseding91 wrote:If you do any of the things listed here it will desync when used in MP and or break replays in single player.
Just FYI.
So what can i do instead to reach my goal Rseding91?
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 1:19 pm
by Adil
AntiElite wrote:
If I use global here, it tells me its not possible in on_load
Well, indeed global cannot be changed during load, the desync explanation from above post is still correct though.
AntiElite wrote:I just want to run a function the tick after loading a game ... not after a player joining ... not before the entitys are loaded ... and without any desync - I've never thought this is gonna be so difficult
Well, for player1 the game is loaded on the tick1 and your function is run on tick1+1, for player2 its the tick2 and tick2+2, how do you expect it be easy not to desync if on each tick script calculated by each player's machine is supposed to arrive in the same state?
If you want changes in some config file to take effect without migrations then just don't store their data in "global." , make that data lua-global (as in, not "local"), lua script files are run on each game load.
Code: Select all
--this is control lua
--these are config variables
local var1=2
var2=3
--this initializes a bit more of config variables
require "config.lua"
--here go functions that use the above variables
...
This will require every player to have same values of config however. And no game objects can be involved.
If you for some reason absolutely need the api-functionality in the config, then you're out of luck.
Re: how to events.on_load in MP without desync?
Posted: Sun Sep 18, 2016 2:17 pm
by AntiElitz
I found out how i can implement what I needed! on_player_joined is fired also in SP when loading a game, but ist fired for everybody in multiplayer as well - so there is no desync. So i just count the number of players on_join and if it's only 1 player online, that will probably a load (unless this is a headless server, but that is fair enought)
Code: Select all
function events.on_player_joined_game(event)
local player_online_count = 0
for key, player in pairs(game.players) do
if player.connected then
player_online_count = player_online_count + 1
if player_online_count >=2 then break end
end
end
if player_online_count < 2 then global.trigger.initialize = true end --will trigger initialization in the mainloop only when first player joins
end
Re: how to events.on_load in MP without desync?
Posted: Thu Sep 22, 2016 5:40 pm
by AntiElitz
RIP solution. Doesn't trigger when loading in Singleplayer. Still looking for an answer, but i fear there is none.
Re: how to events.on_load in MP without desync?
Posted: Mon Oct 03, 2016 2:05 pm
by IngoKnieto
AntiElite wrote: ... So i got a workaround here to make it update on the first tick instead.
Code: Select all
function events.on_load(event)
trigger_on_load = true
end
function events.on_tick()
if trigger_on_load then
init.initialize()
trigger_on_load = nil
end
end
function init.initialize()
step_check_config_changed()
end
How exactly do you run this code? Is it in the control.lua of your mod?
I am basically looking for the same thing: I want to run some code when the game is loaded in SP. However your example isn't working for me; when I put it in my control.lua, it throws this exception: attempt to index global 'events' (a nil value)
Probably I am missing something, any help appreciated

Re: how to events.on_load in MP without desync?
Posted: Mon Oct 03, 2016 9:27 pm
by Adil
Code: Select all
events={}
--previous snip pasted here
--then register the handlers in the following manner
game.on_event(defines.events.on_tick, events.on_tick() )
However, I'd like to recommend once again: rethink your ways if you're in need of this hack.
Re: how to events.on_load in MP without desync?
Posted: Mon Oct 03, 2016 9:29 pm
by aubergine18
About knowing if the game is MP or SP mode, you might like to lend your voice to this topic:
viewtopic.php?f=28&t=33264
Re: how to events.on_load in MP without desync?
Posted: Mon Oct 03, 2016 9:59 pm
by Nexela
Adil wrote:Code: Select all
events={}
--previous snip pasted here
--then register the handlers in the following manner
game.on_event(defines.events.on_tick, events.on_tick() )
However, I'd like to recommend once again: rethink your ways if you're in need of this hack.
Yes this hack will not work in MP and shouldn't be used in a released version. About the only thing this is good for is single player development resetting recipes/code etc instead of always starting new worlds or increment version.
Better config handling will be coming in 0.15
Re: how to events.on_load in MP without desync?
Posted: Wed Oct 05, 2016 6:56 pm
by IngoKnieto
Thank you for all your replies, but I can't get this to work.
This is the complete code from my control.lua:
Code: Select all
events={}
--previous snip pasted here
function events.on_load(event)
trigger_on_load = true
end
function events.on_tick()
if trigger_on_load then
init.initialize()
trigger_on_load = nil
end
end
function init.initialize()
local player = game.players[event.player_index]
player.print("loaded game")
end
--then register the handlers in the following manner
script.on_event(defines.events.on_tick, events.on_tick() )
script.on_event(defines.events.on_load, events.on_load() )
But it still throws the error
attempt to index global 'init' (a nil value) in the line
function init.initialize. What am I missing?
I am still beginning to learn to understand LUA please be patient
Currently I just use this for my personal testing - I want the game to reload base prototypes that I changed with the mod. I understand that migrations would be the best way to do this, I plan to implement it in a later step...
Re: how to events.on_load in MP without desync?
Posted: Wed Oct 05, 2016 7:17 pm
by aubergine18
Code: Select all
-- use local to make it clear if something is local variable or function
local trigger_on_load = false
local init = {} -- you forgot to define this
local events = {}
function events.on_load()
trigger_on_load = true
end
function events.on_tick()
if trigger_on_load then
init.initialize()
trigger_on_load = nil
end
end
function init.initialize()
local player = game.players[event.player_index]
player.print("loaded game")
end
-- if you put () after a function it runs immediately
-- instead just pass in the function reference
-- wrong:
-- script.on_event(defines.events.on_tick, events.on_tick() )
-- correct:
script.on_event(defines.events.on_tick, events.on_tick )
-- ^ removed ()
-- on_load is a special type of event
-- wrong:
-- script.on_event(defines.events.on_load, events.on_load() )
-- correct:
script.on_load( events.on_load )
Re: how to events.on_load in MP without desync?
Posted: Wed Oct 05, 2016 8:16 pm
by IngoKnieto
Huuray it works

Thank you very much for your detailed explanations Aubergine!
I ended up with this code in my control.lua, which very nicely updates recipes or technologies from base game, which I changed in my mod:
Code: Select all
local trigger_on_load = false
local events = {}
script.on_load(
function()
trigger_on_load = true
end
)
function events.on_tick()
if trigger_on_load then
initMod()
trigger_on_load = nil
end
end
function initMod()
for _, force in pairs(game.forces) do
force.reset_recipes()
force.reset_technologies()
end
end
script.on_event(defines.events.on_tick, events.on_tick )
And most important: I learned some LUA

Re: how to events.on_load in MP without desync?
Posted: Thu Oct 06, 2016 7:19 pm
by AntiElitz
this will still cause desync in MP