Race Based Programming Anxiety!

Which method do you guys use to load data for early joiners:

1) Listen for new joiners then load for current players

local PlayerDebounces = {} :: {Player}

--Listen for new joiners
Players.PlayerAdded:Connect(function(Player) 
      if table.find(PlayerDebounces, player) then return end
      table.insert(PlayerDebounces, Player)

      LoadData(Player)
end

--Load for current players
for _, Player in Players:GetPlayers() do
      if table.find(PlayerDebounces, player) then continue end
      table.insert(PlayerDebounces, Player)

     LoadData(Player)
end

2) Load for current players then listen for new joiners

--Load for current players
for _, Player in Players:GetPlayers() do
     LoadData(Player)
end

--Listen for new joiners
Players.PlayerAdded:Connect(function(Player) 
      LoadData(Player)
end

Most people I know use the second method but I have a fear of a player joining in the time between when the loop ends and when the event is creating which results in their data not being loaded at all :grimacing:. Is this valid logic?

ignore any syntax errors

1 Like

Usually the server starts before the client, so you really don’t need to worry about these race conditions unless your code is yielding or something.

That won’t be possible as code runs extremely fast and is unlikely that it will miss a player joining. Another additional tip is to wrap LoadData in a task.spawn while looping through the players in case it yields

1 Like

I may need some more explanation for this. How does your LoadData “work”? I feel like you only need

Players.PlayerAdded:Connect(function(Player) 
      LoadData(Player)
end

This should be enough as it runs extremely quickly with no chance of missing a player.

u sure mate? what if while the event is being added to the event loop a player joins

I don’t know how joining a server works. However, the PlayerAdded event can’t fire while other lua code is running because the firing must happen in the thread that runs lua code. Thus, I’m pretty sure that the PlayerAdded event will fire after the lua code that was running at the time of joining yields.

As @Mystxry12 said, it isn’t possible to miss any player. If you want to be very sure just use task.spawn():

task.spawn(function()
for _, Player in Players:GetPlayers() do
     LoadData(Player)
end
end)

Players.PlayerAdded:Connect(function(Player) 
      LoadData(Player)
end

Which will create a new thread to avoid waiting until the loop ends.

Another reason not to worry is that scripts get loaded as soon as the server is created (which is earlier than players). You can just remove the loop.

1 Like

it doesn’t, there is stuff being done before

Well, to make it slightly faster I would recommend using task.spawn in the for loop, like this:

for _, Player in Players:GetPlayers() do
     task.spawn(LoadData, Player)
end

But you really don’t have anything to worry about.

If you were really that worried, I guess you could put the PlayerAdded connection above the for loop, to make sure you don’t miss a single player.

--Listen for new joiners
Players.PlayerAdded:Connect(function(Player) 
      LoadData(Player)
end

--Load for current players
for _, Player in Players:GetPlayers() do
     LoadData(Player)
end

When the player joins, simply create a new thread for the “LoadData” function, and as far as I’m aware, there shouldn’t be any problems.

You are right, but what I actually meant is that server scripts are already executed before the players join which will avoid this problem.