I have code that moves players to an appropriate team and then reloads their character to move them to the spawn for that team. However, the script sometimes errors if a player leaves the game while performing theses operations.
Simplified Code:
for _,v in pairs(game.Players:GetPlayers()) do
if v.Parent then
v.Team = game.Teams[teamName]
v:LoadCharacter()
end
end
Error: “Failed to apply character appearance, player not in world.”
(Note: I’ve also had errors on the Team assignment before)
This kind of error can make sense; if the loop goes through a lot of players, it may take a while to get to the last player, and they may have left the game.
However, I read previous topics on this issue and believe my error check here should work. If the player has already left the game, v.Parent should be nil, because they are no longer in the game.
Now, I could, theoretically, just use pcall any time I want to do any interaction with player objects, but that sounds…very bad. Is there a better way to secure this loop?
You could add pcall() to it, pcall stops a line(s) of code when error in it occurs, so other code can run without problems. So that code would look like this :
for _,v in pairs(game.Players:GetPlayers()) do
pcall(function()
v.Team = game.Teams[teamName]
v:LoadCharacter()
end)
end
I’d say it is significantly less than 1%, but this is part of the core game logic, so any active server will eventually run into the issue and fail once it happens a single time.
yeah so with some insane luck a person could leave the game as soon as the code go through the if and that is just inevitable so I think pcall is the only option you have
You might find coroutines useful. Since Player:LoadCharacter() yields, the players will respawn one-by-one which is why you are getting the error.
Coroutines can create a new thread for each player to respawn them all at the same time.
Read more about them here.
Honestly, since its a yielding function, promise is your way to go. Its a handy library which is very easy to use.
I believe u cud do smth like this
local loadCharacter = Promise.promisify(function(player)
return player:LoadCharacter()
end)
for _, player in ipairs(Players:GetPlayers()) do
if player then
player.Team = game.Teams[teamName]
characterLoad(player):catch(function(err)
warn(err)
end)
end
end
As you would see, if u tried this out, it wouldn’t break the loop, as the error is caught by the function in :catch, if u also need to do something after the cahracter loads, chain an :andThen to the returning promise.
It is a grt library, and u would understand more if u check out their website and try out stuff.
I have something like this without the warn or catch or promise, it supposed to change everyones GUI on same text and has task.wait(). If a player leaves while this scripts run, the changing of gui will realise one player is missing so it will break the whole script.