I’ve run into an issue that is rare but still possible in testing to reproduce, so it could happen in a public game just as easily. Basically when you assign an object to the Player’s Character, it’s best to use the CharacterAdded:Wait() so the game waits until the object is found/valid/etc. The issue I’ve found with this is that it’s possible for a player to leave the server in a game that even if the object is valid, if the next line underneath it is calling for the Character Position (example), it will error out, crash the script.
Example:
oPlayerCharacter = oPlayer.Character or oPlayer.CharacterAdded:Wait()
-- Some other code in between
oPlayerLastPosition = oPlayerCharacter.HumanoidRootPart.CFrame.Position
It’s possible for the player object to be found and the player leave the server before even the next line of code runs, at which point, the character is gone and the object is invalid to assign the position, which blows up later in the code because of this. Is there a way I’m missing (and haven’t found through the web search here) that some of more veteran coders know a way to double-check this later in your script code? So, some lines down when I want to get that CFrame position, I thought using some like this would prevent this from happening, but I guess I’m not using the best way to check for a valid player object?
if oPlayerCharacter then
-- Do some stuff here assuming the player object is still valid
end
Ok, seems I found the answer, by some trial and error. I didn’t think I would solve this so fast but maybe this will save someone else the quest in the future.
So, anything that will access the player character object later in your code I thought would be screened by
if oPlayerCharacter then
-- Do some stuff here assuming the player object is still valid
end
But after a lot of testing with some players and spam connecting/disconnecting from the server (LOL), found that this actually works to stop those rare edge case issues. I don’t know why didn’t think of this before, but when you have so many coding languages in your head it takes a while to get your thoughts together on what it takes to reach the goal.
if oPlayerCharacter ~= nil then
-- Do some stuff here assuming the player object is still valid
end
Aren’t those two statements equivalent? How did it fix your problem? Lua considers false and nil to be falsey. And I’m guessing you’re trying to check if the oPlayerCharacter is true, so if it exists the code should run the same on both if statements right? Or am I missing something on your solution
I thought they were too, but without looking at the actual game engine code, my guess is that this simple test:
if oPlayerCharacter then
-- Do some stuff here assuming the player object is still valid
end
Will return true (incorrectly) because the Player Object still exist but the Character Object attached to it is gone. My guess it would look like PlayerObject.nil vs. PlayerObject.CharacterObject and the If statement is only checking if it is “valid” in that it is because nil is attached to something valid, the PlayerObject.
Using the “not nil” statement might have it look at same object (that should be gone) and the .nil part is enough to trigger a “oops, object is actually gone”.
This is all guessing at this point,but it seems to solve my issue. I’ll be happy with that.
Here is another check I found that is useful against players who try to exploit this against the server and cause scripts to crash doing checks on valid Characters but with the body parts gone. This can be caused by players exploiting the built-in character reset. I know I’ve seen this on a lot of servers where those exploit players crash the NPC scripts (the NPCs stop functioning for example out of the blue) You can replace the part with any part you are actually looking for, they usually delete the HumanoidRootPart as the most likely way to cause a problem.
if oPlayerCharacter:FindFirstChildWhichIsA("Part") then
-- Do some stuff here assuming the character object is still valid and they did not delete their own body parts
end
Those statements are equivalent, any differences experienced between the two are purely arbitrary. If you need to wait for a player’s character’s appearance to load listen to that player’s ‘CharacterAppearanceLoaded’ event/signal.
It can, but at least one can check for the part before doing something with it before something deletes it. I didn’t make a good example as I would be checking for the HumanoidRootPart as an example.
Yes, that was the root issue of my original post at the top. I did get a response from the devs and they are aware of the issue. As I mentioned, it’s an edge case and they know how to reproduce it so for now, I have a workaround until I read about it in a future update about engine fixes, etc.
Mind sharing a screenshot of official Roblox staff acknowledging this as an issue? The code you provided errors because the character model no longer exists, you need to create a direct reference to the character model’s ‘HumanoidRootPart’ part instead.
local Model = Instance.new("Model")
Instance.new("Part", Model)
Model:Destroy()
print(Model.Part.Position) --Errors.
local Model = Instance.new("Model")
local Part = Instance.new("Part", Model)
Model:Destroy()
print(Part.Position) --0, 0, 0
that was the root issue of my original post at the top.
As stated here that warning is completely unrelated to the thread.
It’s an engine issue more than a script issue, but I didn’t know that after I posted here. Here is an example code to replicate the issue if that helps those interested in this topic. What happens is, if the player leaves the server between when the script checks if the player object is still valid and before it assigns the player character to the object, two things will happen. It will get “nil” as the player and character objects are now gone and when it does the check that the character object is still valid, instead of failing, it passes for some reason, which will then crash the script because when it tries to get the character object name, it will error out with the nil index. The second thing that can happen is that it gets stuck on the oPlayer.CharacterAdded:Wait() and never finishes, no errors, no yield errors, etc. Either way, the script either crashes or freezes forever. It’s hard to duplicate trying this in the Studio with 0 ping times doesn’t seem to happen, but on a public server, you can make it happen a lot more than you think you should be able to. I am able to reproduce it quite reliable now on a public server, though I have it setup to demonstrate the edge case. Also, posting up a screenshot of what the staff is sending me is private and inappropriate that I have to prove my issue to non-staff people here. For that request, I will deny it.
function GetPlayerOne()
for _, oPlayer in pairs(game.Players:GetPlayers()) do
return oPlayer
end
return nil
end
local oPlayer = GetPlayerOne()
local oPlayerCharacter
while true do
if oPlayer then
oPlayerCharacter = oPlayer.Character or oPlayer.CharacterAdded:Wait()
if oPlayerCharacter then
print("Player Name: " .. oPlayerCharacter.Name)
end
end
wait(1)
print("Loop")
end