What do you want to achieve? Our game has a city for players to walk around and roleplay in. We also have minigames that take place every couple of minutes in a designated area of the map. Players can join the queue for minigames by pressing a button in the game world and be moved to the minigame area when the next minigame begins. When the minigame begins, we set the player’s RespawnLocation to one inside the minigame area, and then call player:LoadCharacter() to respawn them inside the minigame.
What is the issue? Sometimes we get the error “Failed to load character appearance, player not in world”. Immediately before calling player:LoadCharacter() we check if player.Parent == Players. Specifically, our reference to the Players service is through a module script called MinigameBase, the same module script that this code runs in. The exact code is:
if player.Parent == MinigameBase.Players then
player:LoadCharacter()
else
continue
end
What solutions have you tried so far? We’ve looked for solutions in other threads and they all say to use a check similar to what we have above, some preferring to use Players:FindFirstChild(player.Name) which is basically the same check with extra steps. Some suggest a direct reference to game.Players but that seems as good as the current reference, unless references through module scripts can fail?
Is it possible for someone to logout exactly between checking if the player is on the server and loading their character? Do we need to always put anything player related inside of a pcall, spawn, or coroutine?
Players use a button to join a minigame queue while waiting for the minigame to start. When the queue time has elapsed, players in the queue are moved to the minigame. New players being added to the game do not automatically join minigames.
Alright well I still believe you can wrap this in a PlayerAdded event since apparently they still have to click a TextButton or something in order to join the queue, so this actually wouldn’t immediately put the player into a queue.
I don’t understand the suggestion, can you give an example? The problem is not with loading their character when they join the server (when the PlayerAdded event is fired). Here is our current process:
Player logs into the game and their character is loaded. This works fine.
Player joins the queue for the next minigame.
Minigame queue timer counts down
When the minigame queue timer reaches 0, all players that are queued for the minigame have their RespawnLocation set to inside the minigame, and we try to LoadCharacter(). This is where it is failing.
By the time we need to load their character into the minigame, the player has been in the game with a character already loaded for up to 60 seconds.
It is my understanding that Players on the server are always a child of the Players service, that is why we check “player.Parent == game.Players” immediately before loading the character. If the player is not a child of the Players service, their character will not be loaded.
The issue is that we check that they are a child of the Players service, which should mean they are on the server, yet when we call LoadCharacter() it sometimes still fails saying they are “not in the world”.
The issue is that you are not using the actual player instance. The actual player reference is inside game.Players. If you store their character inside MinigameBase.Players you could do:
local Players = game:GetService("Players")
--function that returns the player reference, from their character
local actual_player = Players:GetPlayerFromCharacter(player)
if player.Parent == MinigameBase.Players then
actual_player:LoadCharacter()
else
continue
end
For me to assist you further, I have to know how you store players inside MinigameBase. Although the main idea is to convert your player reference to the actual one, and use LoadCharacter on it.
some functions that may help: Players:GetPlayerFromCharacter(player) Players:GetPlayerByUserId(userId) Players:FindFirstChild(username)
PS: The actual player object is only inside game.Players
Have you tried accessing the service directly? replacing MinigameBase.Players with game.Players may fix it if the error is related to garbage collection.
New code with a pcall and using game.Players still fails and does not return success or failure and nothing after the pcall in the script runs:
if player.Parent == game.Players then
print("Loading character")
local success, message = pcall(function()
player:LoadCharacter()
end)
if success then
print("Loaded character")
else
warn(message)
end
else
print("Player offline, skipping setup")
continue
end
Sorry I misunderstood it. I thought the problem was with the Player not being in the game yet.
I’m not exactly sure of any other purposes of you having LoadCharacter() there other than to respawn the player at another spawn point, which is basically teleporting them, so would it be possible as a temporary fix to just set the HumanoidRootPart’s Position to the SpawnPosition for now, or would that mess up other things?
Yeah that would mess up other things. When the minigame begins we do a lot of things to the player such as change their team, remove their tools, etc. Also I’ve always had trouble in the past with teleporting and seats. We have a lot of seats, including vehicles, in our game and it’s unreliable trying to remove them from the seat before teleporting them.
In the end we determined respawning was the safest option but it appears there is a bug with player:LoadCharacter() if the player logs out in the middle of it; sometimes it will completely stop the thread it is being run in.
To get around it for now we’ve wrapped player:LoadCharacter() in a coroutine, since even pcalls fail to catch whatever error it throws when someone logs out during it. There’s another thread about it in the Engine Bugs forum, linked above where I go into a bit more detail.