Page 1 of 1
Multiplayer / global and player index or name ?
Posted: Mon Apr 25, 2016 10:20 pm
by binbinhfr
Hi,
I try to write MP compatible mods, but I still have one doubt :
Let say I want to record some player-specific data into table global.test, to save these data with the game.
Should I index this table with player index ? or player name ?
In other terms : if a player disconnect from a MP game and reconnect later, will he recover the same player_index ?
Or should I only trust the player name ?
What about the event "on_player_created" ? Is it called each time a player connect to a MP game ? Or only the first time ?
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 7:07 am
by Rseding91
Player index is unique per player instance.
Player name can be anything and is not unique.
on_player_created is only fired when a new player joins the game.
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 7:21 am
by binbinhfr
Rseding91 wrote:Player index is unique per player instance.
Player name can be anything and is not unique.
on_player_created is only fired when a new player joins the game.
Ok for unicity of player_index.
But can you explain what happen when a player connect or reconnect to a MP game ?
How my mod can detect that ? How can I trigger some initialization of some global player parameters at this time ?
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 7:24 am
by orzelek
binbinhfr wrote:Rseding91 wrote:Player index is unique per player instance.
Player name can be anything and is not unique.
on_player_created is only fired when a new player joins the game.
Ok for unicity of player_index.
But can you explain what happen when a player connect or reconnect to a MP game ?
How my mod can detect that ? How can I trigger some initialization of some global player parameters at this time ?
You need to use player created event and then store global info in table indexed by player number in global data.
Thats how I seen it done in some mods - didn't use it myself so not 100% sure.
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 10:02 am
by binbinhfr
orzelek wrote:
You need to use player created event and then store global info in table indexed by player number in global data.
Thats how I seen it done in some mods - didn't use it myself so not 100% sure.
ok, it seems logical.
The problem with MP mod testing is that you have to find a fellow tester

By the way, is there any trick to test a MP game alone ? Or do I have to get 2 factorio licences to run 2 players on 2 machines ?
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 10:08 am
by Zeblote
You could get the zip version from the download site and just unpack it a few times, then start each instance
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 10:10 am
by binbinhfr
Oh yes, one other situation is :
the MP game already exists, with players in it.
And they want to add my MP mod.
Then no player_created event is triggered...
So I suppose I have to use event configuration_changed to initiate my globals for every player present at that moment in game.
But in this event, the game and the players do not already exist if I'm correct...
So maybe the general trick could be to check the creation of these global_per_player in on_tick at tick 0...
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 11:10 am
by bobingabout
tick_0 is game tick 0, doesn't work that way.
Anyway... if you define a variable in global... all players will have access to this if they were connected when it was created or not.
If you define a function in a local, then that function exists regardless of when the player connected.
And player data is stored even when the player logs off, that way the player gets their stuff back when the log back in. There is a variable to check to see if a player is currently connected or not.
You only need to worry about the on_configuration_changed and on_player_created the FIRST time they're created
So if you need to create a global per player, then iterate though the players in on_configuation_changed, then add for the new player only on on_player_created.... make sense?
Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 12:42 pm
by binbinhfr
tick_0 is game tick 0, doesn't work that way.
oh yes, I did not mean tick 0 but first tick of the session (first call to on_tick), just when a player open a saved file.
bobingabout wrote:
So if you need to create a global per player, then iterate though the players in on_configuation_changed, then add for the new player only on on_player_created.... make sense?
Yes it's very clear, thanks for your help.
I just thought that game.players was not already available in on_configuation_changed (as in On_load or on_init). So obviously it is

Re: Multiplayer / global and player index or name ?
Posted: Tue Apr 26, 2016 1:45 pm
by bobingabout
binbinhfr wrote:I just thought that game.players was not already available in on_configuation_changed (as in On_load or on_init). So obviously it is

The only place it isn't as far as I can recall, is on_load.
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 10:20 am
by binbinhfr
bobing,
even if I know that it is not the perfect way to do it, can you explain to me why this simple code is making a kind of desync loop (creating endless "desync report") when I connect solo on a headless server running it ?
Code: Select all
require("defines")
local is_first_tick = true
function on_tick(event)
if is_first_tick then
is_first_tick = false
for _, player in pairs(game.players) do
player.print("hello")
end
end
script.on_event(defines.events.on_tick, nil )
end
script.on_event(defines.events.on_tick, on_tick)
For me, this program should print hello to all players, everytime a new player connects and calls on_tick for the first time.
Infect it works at the first connection. But then if I decon and recon, there is the non-resolving desync loop.
I do not understand what is exactly happening that disturb the program. Should it be this local variable ?
The underlying question is : what is detected by the program as a desync ? Does it compare full memory of different peers byte by byte, and if there is one little difference, then it's a desync ? So to be MP compatible, there should be no local variables outside of a function (unless the local is used as a constant, I suppose) ?
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 11:31 am
by bobingabout
From what I understand it, there is a desync because local is just that, local, so the information from one client is different from another, in that the newly connected player has the local set to true, yet everyone else has it set to false. on top of that, the code works in such a way that it speaks for everyone (the game.players loop)
I think what you need to do is change your approach. Now I'm not a lua scripting expert, so I don't know if the hook I'm thinking of even exists, but what you need is an on_player_connected event, and use that instead of a local.
you should probably also check to see if game.players.connected is true before sending them a message.
in fact, If you want to get smart, you could save in a global the state of game.players.connected for every player, compare this tag of every player to your saved state every tick, and then relay the message if it changes for any reason. Just don't forget to take into account that new players can be created too.
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 12:50 pm
by Choumiko
on_player_connected/joined will be in 0.13.
The reason for the desync is that on_load is only executed for the joining player. As a result in the next tick only he has on_tick registered, all other players(and the headless server(which afaik isn't a real server, just a player without character)) have no on_tick handler -> desync
Here's a modified/stripped down version of a mod i'm working on: (which will add a few additional events)
global.player_data looks like { [1] = {player=game.players[1], connected = true } ,[2] = { ... } }
Code: Select all
--in on_player_created do:
global.player_data[event.player_index] = {player=game.players[event.player_index], connected = true}
--in on_tick: (every few ticks)
for _, player_data in pairs(global.player_data) do
local player = player_data.player
if player.connected then --currently connected
if not player_data.connected then -- wasn't connected last check
Events.dispatch_player_connected(player_data)
player.print("hello")
end
else -- player isn't connected anymore
if player_data.connected then -- was connected last check
Events.dispatch_player_disconnected(player_data)
end
end
player_data.connected = player.connected
end
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 1:13 pm
by binbinhfr
Thanks for your ideas.
Alas, there is a player_created event, but no player_connect.
And by the way, the on_load event does not know about game.players yet, but on_init and on_config_changed can read game.
After several tests, the solution is, whenever you want to work on players, to parse the whole player list and to test player.connected before doing your stuff.
And to use player_created event if you want to initialize specific player variable, create a always-opened gui, etc...
And as choumiko says, you can track connected status in on_tick if you don't want to check player.connected everytime you need it.
"on_player_connected/joined will be in 0.13." Nice ! Will it be trigger for all players or only the already connected ? Because the connected one already triggers on_load, as you said.
By the way, if on_load is only triggered for the newly connected player, won't it always cause desync ? What can we do with it ?
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 1:33 pm
by Rseding91
binbinhfr wrote:By the way, if on_load is only triggered for the newly connected player, won't it always cause desync ? What can we do with it ?
If you do things wrong in your mod - yes. As seen before with the local "first_tick" variable which caused a desync because it was using on_load wrong.
on_load is meant for 2 things and only 2 things:
Re-register conditional event handlers
Re-setup meta-tables
It should never change the game state and should never change the global table of the mod.
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 1:54 pm
by binbinhfr
OK, it becomes clearer now. Not always easy to try to imagine of factorio really works in depths.
By meta-tables, you mean lua tables containing references to entity or game stuff like that ? I do not see what kind of tables you would like to create and need to repopulate, that cannot be stored into global ?
By the way, can you explain the "desync" detection ? Is it pure memory comparison ?
So then, again, if only one peer repopulate a meta-table, wouln't it create a memory desync ?
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 1:56 pm
by prg
Rseding91 wrote:on_load is meant for 2 things and only 2 things:
Re-register conditional event handlers
Re-setup meta-tables
Are metatables officially supported by now? Last thing I heard,
they weren't. If they are, why aren't they saved like any other table? There's a getmetatable (or lua_getmetatable from the C side) so this should be possible, no?
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 1:58 pm
by prg
binbinhfr wrote:By meta-tables, you mean lua tables containing references to entity or game stuff like that ?
Metatables and Metamethods
Re: Multiplayer / global and player index or name ?
Posted: Wed Apr 27, 2016 2:23 pm
by binbinhfr
Well I really learnt a lot of new things today ! Thanks all. I'll go and update my mods to make them MP proofed
