Can scripts break mid way if a player leaves?

I know it may be rare since scripts are executed very quickly usually. But it can still happen, I’m talking about server side code because client-sided code will just be removed from the game once the client leaves.

Wouldn’t this mean that I’d have to wrap anything related to the player in a pcall 90% of the time? If statements don’t really help cuz a player could leave at a different moment in time.

Pcalls are quite light on resources right?

Here’s some example code where it could happen I assume I’m correct in saying that the scripts could break here if a player leaves. Rendering systems functionless.

Game.Players.PlayerAdded:Connect(function(plr)
Local leaderstats = instance.new(“folder”)
Local leaderstats.Name = “leaderstats” 
Leaderstats.Parent = plr — nil and player leaves here
end)

RE.OnServerEvent:connect(function(plr)
If plr then
If plr.leaderstats — Attempt to index nil with player again cuz player left right here
End
end)

While true do
For _, player in game.Players:GetPlayers() do
Player.leaderstats — Attempt to index nil with leaderstats cuz player left here
end
task.wait()
end
2 Likes

The documentation for Player and Players.PlayerAdded/Removed implies that the server only parents a Player instance to nil when they leave, and not destroys it. Your code should be fine since the Player instance shouldn’t be actually destroyed until nothing is referencing it anymore.

2 Likes

All of my code? Even the ones in while loops?

1 Like

If your code has a reference to the Player instance, then it means it shouldn’t be destroyed yet reasonably if it’s only been parented to nil.

1 Like

The code will work just fine, event calls are wrapped so if an error is thrown it will not break the whole script.

Ah okay, what about if i’m using the player object in a while loop for example?

This was true for some time, up until recently:

Your current code will return all instances of players so it should not create problems, is there a specific need for the loop?

It was just example code I wrote up on my phone I’m not actually using any of this code lol. But you know some people may have code for those games like “you get +1 time every millosecond” or something

But what if a player just leaves at the exact moment in time? Surely the player’s object will become nil after they leave.

while true do
for _, player in Players:GetPlayers() do
player.leaderstats.Time.Value += 1 -- Player leaves EXACTLY at this point in time
end
task.wait(.1)
end

Unless there’s some sort of feature roblox has that prevents this? Could you explain to me why this wouldn’t break the script if a player left at this exact moment in detail please?

It will not become nil.

If a variable holds a reference to an instance, the variable still contains the value even if the instance is destroyed.

This is actually a common memory leak issue.

Unless your code is yielding in some way, it’s highly unlikely that it is receiving an already destroyed Player instance at the moment GetPlayers is called, so there’s no reason to worry about it. At best if you’re really concerned about it you could wrap the section inside of the for loop in a task.spawn() to prevent it from disrupting the entire loop:

while true do
    for _, player in Players:GetPlayers() do
        task.spawn(function()
            player.leaderstats.Time.Value += 1 -- Player leaves EXACTLY at this point in time
        end)
    end
    task.wait(.1)
end

His concern is valid though because a destroyed instance means that all of its descendants are also destroyed, making it so that the attempt to edit leaderstats would result in a child not found error.

1 Like

The only thing that I could see throwing an error here is the leaderstats folder or the Time value not being found, if you’re concerned about it just throw it in a pcall.

1 Like

I know I could throw in pcalls but I was wondering if it was necessary I just had this thought come in my head a few days ago and i’ve never seen many people really talk about it.

Not necessary, but for the example you provided the main concern is not the player, but if the contents like leaderstats and Time are present. Other than that there is no other worry.

That’s the problem, I know references to the player object is saved but if you write a player object up in your code 90% of the time you will index it with something like leaderstats which could throw an error if the player leaves at the exact time no?

That would happen if you attempt to check for those objects before they are initialized (like the loop in this case), but again, if you are afraid of an error being thrown for when the player leaves just wrap it in a pcall since otherwise it would break the whole loop.

If you’re worried about players becoming invalid during script execution, include basic checks for important things. You could use protected calls, but it’s also good practice to do validity checks.

Example, checking if leaderstats still exists:

while true do
   for _, player in Players:GetPlayers() do
      if player:FindFirstChild("leaderstats") then
         player.leaderstats.Time.Value += 1 -- Player leaves EXACTLY at this point in time
      end
   end
   task.wait(.1)
end

Also for this specific code example you gave here, afaik it’s not possible for the player to become nil between the for _, player declaration and the code within the for loop. You gathered all of the currently existing players at that instant in time and instantly execute the code. If the player leaves on the same tick, they will not be collected in the Players:GetPlayers() method.

Destroying an object only sets the parent to nil and cleans up connections, the instance itself still exists until it’s garbage collected when there are no references to it left. You can still reference the player object for as long as you want.

1 Like

Using the second argument to FindFirstChild may be beneficial in regards to this as well.

local TimeVal = player:FindFirstChild("Time", true)
if TimeVal ~= nil then
    TimeVal.Value += 1
end
1 Like