Multiplayer / global and player index or name ?

Place to get help with not working mods / modding interface.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Multiplayer / global and player index or name ?

Post 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 ?
My mods on the Factorio Mod Portal :geek:
Rseding91
Factorio Staff
Factorio Staff
Posts: 15938
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Multiplayer / global and player index or name ?

Post 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.
If you want to get ahold of me I'm almost always on Discord.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 ?
My mods on the Factorio Mod Portal :geek:
orzelek
Smart Inserter
Smart Inserter
Posts: 3928
Joined: Fri Apr 03, 2015 10:20 am
Contact:

Re: Multiplayer / global and player index or name ?

Post 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.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 ?
My mods on the Factorio Mod Portal :geek:
Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Multiplayer / global and player index or name ?

Post by Zeblote »

You could get the zip version from the download site and just unpack it a few times, then start each instance
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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...
My mods on the Factorio Mod Portal :geek:
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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?
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 :-)
My mods on the Factorio Mod Portal :geek:
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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) ?
My mods on the Factorio Mod Portal :geek:
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Choumiko
Smart Inserter
Smart Inserter
Posts: 1352
Joined: Fri Mar 21, 2014 10:51 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 ?
My mods on the Factorio Mod Portal :geek:
Rseding91
Factorio Staff
Factorio Staff
Posts: 15938
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Multiplayer / global and player index or name ?

Post 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.
If you want to get ahold of me I'm almost always on Discord.
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 ?
My mods on the Factorio Mod Portal :geek:
User avatar
prg
Filter Inserter
Filter Inserter
Posts: 947
Joined: Mon Jan 19, 2015 12:39 am
Contact:

Re: Multiplayer / global and player index or name ?

Post 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?
Automatic Belt (and pipe) Planner—Automate yet another aspect of constructing your factory!
User avatar
prg
Filter Inserter
Filter Inserter
Posts: 947
Joined: Mon Jan 19, 2015 12:39 am
Contact:

Re: Multiplayer / global and player index or name ?

Post by prg »

binbinhfr wrote:By meta-tables, you mean lua tables containing references to entity or game stuff like that ?
Metatables and Metamethods
Automatic Belt (and pipe) Planner—Automate yet another aspect of constructing your factory!
User avatar
binbinhfr
Smart Inserter
Smart Inserter
Posts: 1525
Joined: Sat Feb 27, 2016 7:37 pm
Contact:

Re: Multiplayer / global and player index or name ?

Post 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 :-)
My mods on the Factorio Mod Portal :geek:
Post Reply

Return to “Modding help”