Do Server Scripts run before the Player joins?

Lets say I have a server script that executes the following code:

game:GetService("Players").PlayerAdded:Connect(function(Player)
    print(Player.Name)
end)

Would it be possible for a Player to join before this code executes? If that were the case, how would you avoid that? I am currently using one script architecture with Module loading and I have Server Scripts with a PlayerAdded event listener, and I am worried if a case like this were to happen.

6 Likes

Server scripts run before any player is added to the game.

If you do want to have a server script run AFTER the play joins then you would add something like this at the top of your server script.

local Players = game:GetService("Players")
Players.PlayerAdded:Wait()
4 Likes

What about modules? Like I said I’m using a one script architecture where I have one server script that loads a bunch of modules. One of those modules is called a “Data” script. Inside of this contains a playeradded event.

2 Likes

Module Scripts are there too, so long as it isn’t parented to a running local script.

Normally what happens is that the Server already has it’s contents there and it’s loaded. When a player is added, then the player actually downloads (replicates) information from the server.

1 Like

Alright but what if I’m loading modules and the Data Module is the last one to load, and players have already joined before the Data module has loaded? What do you do then?

2 Likes

In most cases I’ve had server scripts run before the player joins. As long as you don’t yield you shouldn’t need to worry about this happening but if you’re still worried, this is something you can use to make sure

local Players = game:GetService("Players")
function PlayerSetup(player)
	-- insert code you would usually put in playeradded here
end
for _, player in pairs(Players:GetPlayers()) do
	PlayerSetup(player)
end
Players.PlayerAdded:Connect(PlayerSetup)

EDIT: The code above is fine if you don’t have anything in PlayerSetup that yields, but if the code you’re putting in PlayerSetup yields please see this reply

12 Likes

In what scenario did you have to where server scripts ran before you connected a function to the player added event?

2 Likes

The server will only accept players after all scripts yield. Roblox Lua runs on one thread so all queued tasks will finish before a player event is triggered on the Lua side.

1 Like

So in conclusion, any Server Scripts that run and any Server Scripts that require modules will all run before the Player joins the server no matter what? I’m mainly concerned by this because I have a Data Module which will do certain things with the Player’s Data once a Player joins.

2 Likes

yes as long as the module does not include a yield. Im guessing at the issue being related to a datastore call as it is a yield function (GetAsyn / SetAsyn ect).

1 Like

Are Yields things like wait() and RunService.Heartbeat:Wait()

2 Likes

yes. Anythign that will cause a delay / pause in the execution of the code. They should also be noted on the api page like so

1 Like

A very long time ago I used to use a weird method of making sure all of the places in my game had the same code and instances required to run the game before packages were added to Roblox (there may have been better methods that I didn’t know of at the time though…) It was a script placed in all the places and it used InsertService to insert a model that would contain all game data which would then move all of the instances to the correct places they should be in. I ran into an issue where the first player to join the server were being placed in before InsertService was done downloading the model which meant PlayerAdded was being fired before the scripts were ready so I had to use code similar to the one I wrote there so it wouldn’t be a problem anymore

6 Likes

LexiDog5’s answer is the correct and standard way to approach this issue. You should always handle player added functions in this way. OP should mark it as the solution so the rest of the replies don’t confuse anyone else with the same question.

8 Likes

Okay so do Loops cause a delay or creating huge amounts variables or using functions?

1 Like

They will not cause the code to yield.

Modules should be loaded in when needed e.g. lazy loading.

If you have a setup that is needed for when a player joins then just require it inside the event. A module runs once after which a cache is returned.

game:GetService("Players").PlayerAdded:Connect(function(Player)
     local module1 = require(module 1) -- setup
end
1 Like

There is a caveat to this solution that should be kept in mind. If PlayerSetup never yields, then the code is correct. However, if yielding is possible, then some minor adjustments should be made:

local Players = game:GetService("Players")
function PlayerSetup(player)
	-- insert code you would usually put in playeradded here
end
-- Connect the listener *first*.
Players.PlayerAdded:Connect(PlayerSetup)
for _, player in pairs(Players:GetPlayers()) do
	-- Run setup in a coroutine (use preferred spawning method).
	coroutine.wrap(PlayerSetup)(player)
end
-- More code can safely be added here.

In this particular case, connecting the listener first isn’t necessary, but it’s good practice anyway.

5 Likes

I’ve edited my post to link to yours at the end, thanks for mentioning that

2 Likes