I was having difficulties with the PlayerAdded event running before the listener had time to finish loading. After looking around I found a solution given by two separate Roblox staff members that included a small restructuring as well as a for loop. Here is an example of the code before and after:
BEFORE works about 70% of the time:
players.PlayerAdded:Connect(function(player) --code to initialize session tables and such end)
AFTER playerAdded works 100% of the time:
local function playerAdded(plr) --code to initialize session tables and such print("This runs once") -- prints only once end for _,player in pairs(players:GetPlayers()) do print("test") -- never prints playerAdded(player) end players.PlayerAdded:Connect(playerAdded)
My question is: why doesn't it print out anything in the for loop? The for loop isn't nested within an if statement or some other loop; it is at the highest scope within the script, so it runs after all the variable declarations and such.
I was hesitant to use this for loop because it seemed as though playerAdded will run twice, but it doesn't, why? I'm happy it works, but I'd rather understand why it works. Thank you for the help.
[EDIT] I'm well aware this is a solution to a studio play-solo bug. The for loop isn't needed on a live server, but I test A LOT and can't afford for 30% of my tests to be botched over something that is easily remedied. I'm mainly interested in how it seems to be reading it, but not executing.
[EDIT] I tried replacing the player object with a static "test" string and it still doesn't show up. Also, I had prints inside the function that work (how I caught the odd behavior in the first place).
The reason this only runs once is a combination of what everyone said in the comments. (I wish I could divide the answer up since everyone in the comments were correct, so I'll just upvote them).
If you add a wait at the very top of the script, "test" will suddenly start printing, and the playerAdded function still only runs once. It's almost like an invisible if statement. If the script takes too long, then the player has already been loaded, then it will run the for loop (since the player is retrieved within get players) and ignore the .PlayerAdded:Connect(playerAdded) hook because the player was already added.
If you remove the wait and simulate a very fast loading script, then the for loop will return a blank table and skip it. The hook immediately follows, so it will set up the hook by the time the Player actually loads in. This will cause the PlayerAdded event to fire instead of the for loop.
Thanks to all in helping me figure this out. I'm wondering if I can use this elsewhere now.