How to find HumanoidRootPart after death?

Thank you, this does update the characters table perfectly! I have implemented the break thing, but it does not solve the problem since the script throws an error since it went past the char exists check and then the player died and after cannot find humanoid root part’s position.
I have tried putting it in a pcall statement but that didn’t work either. Do you know if there is a Lua equivalent to the Python ‘try’?

1 Like

Yes, in Lua, you can use the pcall function to catch and handle errors similar to the try-except block in Python. The pcall function stands for “protected call” and allows you to execute a function and catch any errors that occur!

Here is an example of how you can use pcall to handle errors when finding the HumanoidRootPart

for i, character in ipairs(characters) do
    local success, humanoidRootPart = pcall(function()
        return character:WaitForChild("HumanoidRootPart")
    end)

    if success then
        -- HumanoidRootPart found, continue with your code
    else
        -- Handle the error when HumanoidRootPart is not found
        print("Error: " .. humanoidRootPart)
        -- You can choose to break the loop or handle the error in a different way
        break
    end
end

You can then check the success variable to determine if the HumanoidRootPart was found or if an error occurred. If success is true, you can continue with your code. If success is false, you can handle the error in the else block.

1 Like

Still get a warning which stops the script :frowning: Infinite yield possible on 'Workspace.Omnomc:WaitForChild("HumanoidRootPart")'

local success, hrootPos = pcall(function()
    return char:WaitForChild("HumanoidRootPart").Position
end)
1 Like

Just to let you know, WaitForChild will not error at all.

If the timeOut argument is not specified, it will simply yield forever (and will simply give a warning after 5 seconds). If you need it to return nil, specify the timeOut.

2 Likes

The warning you’re seeing, “Infinite yield possible”, occurs because the WaitForChild method is a yielding function. When you use pcall to wrap a yielding function, it can potentially cause an infinite yield if the function being called never completes

To avoid this warning and prevent the script from stopping, you can use a non-yielding alternative to WaitForChild, such as FindFirstChild. Here is an example:

local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
    local success, hrootPos = pcall(function()
        return humanoidRootPart.Position
    end)
    
    if success then
        -- HumanoidRootPart found, continue with your code
        print(hrootPos)
    else
        -- Error occurred, handle it gracefully
        warn("Error: " .. hrootPos) 
        -- You can choose to break from the loop or continue with other characters
    end
else
    -- HumanoidRootPart not found, handle it gracefully
    warn("HumanoidRootPart not found")
    -- You can choose to break from the loop or continue with other characters
end

By using FindFirstChild instead of WaitForChild, we avoid the potential for infinite yield and the associated warning.

Not sure 100% this will solve your problem:(

1 Like

A few things I want to clear up in this conversation:

  1. Don’t assume HumanoidRootPart will always exist.
    Technically, CharacterAdded will fire and guarantees all the Humanoid and it’s limbs will exist, but when referencing a character, there is a possibility the HumanoidRootPart will be gone (like falling off the map).

  2. If the HumanoidRootPart is constantly not being found, answer these questions:

  • Is your character reference always up-to-date? - Player.Character is a property with a value of the current existing character. If the player respawns, the old character is no longer referenced.
  • Is Players.CharacterAutoLoads set to true and you are spawned in when the code runs? - If this is set to false, the player will not respawn, therefore not updating the Character property.
  • Is your HumanoidRootPart being renamed somehow? - Check the explorer window to see if HumanoidRootPart actually exists.
  • Are you using a custom character model? - You may not have a part called HumanoidRootPart.
  1. You can technically have a top-level characters variable, but you would have to constantly update that table whenever the a player respawns. If you want to guarantee characters with HumanoidRootParts, consider this pattern instead:
local function getCharacters(withHumanoidRootPart: boolean?): {Model}
    local characters: {Model} = {}

    for _: number, player: Player in Players:GetPlayers() do
        if player.Character ~= nil then
            if withHumanoidRootPart == true and player.Character:FindFirstChild("HumanoidRootPart") == nil then
                continue
            end

            table.insert(characters, player.Character)
        end
    end

    return characters
end

-- teleport all characters with HumanoidRootParts
for _: number, character: Model in getCharacters(true) do
    character.HumanoidRootPart.CFrame = CFrame.new(100, 100, 100)
end
1 Like

It will work on server-side too, the server-script will be parented to each character. So the parent of that server-script will be the parent of that character. It’s basically local (sort of)

1 Like

How would you get the scripts to run parented on all chars since StarterPlayerScripts only works with local ones?

That’s not true, don’t know who told you that. Both local and server scripts work on starterplayerscripts.

I tried a print statement in a script in starterplayerscripts and it did not print
image

Within your if statement here is what you should do in different scenarios:

While loop:

while rootpart do
task.wait(5)
print(rootpart.Name)
end

It will only run the code while the root part exists.

If statement with delay:

local rootpart = character:WaitForChild(“HumanoidRootPart”, 10)
if not rootpart then return end
task.wait(0.5)
if not rootpart then return end
--do as you wish with the root part

All you need to keep in mind is that whenever you wanna do something with the root part it may or may not exist. On the line before you manipulate it, check if it exists. If not, exit the function if the rest of the function is related only to the root part.
Exit a function using return, or a while or for loop using break. If the for loop is iterating instances of which you must check more, use continue.

What if the function contains other important things that are unrelated to the root part? Then simply wrap all code relating to the root part in an if statement which checks for the root part’s existence, or start an entirely new local function dealing with the root part with our previously mentioned error-prevention methods within.

1 Like

Thank you, thank seems to work! Since the loop will stop for 10 seconds if they cannot find the player, I am worried this could be exploited. Do you know if running each char in the pairs(characters) loop in parallel would prevent this issue, and if so, how?

I’m not sure I know exactly what you’re talking about, mostly because I’m not sure in what way the script will be trying to access the root part. You can adjust the 10 to a shorter time such as 1, or perhaps 2, if your worried about the code yielding for too long.

If even 1 second is too long, then yes, running the loops in parallel would be much better since one yield wouldn’t stop the entire for loop. I need to understand better in what way you’re accessing the root part, can you post that section of the code?

Sure, by exploiting I mean deleting the humanoid over and over again locally to stop the script from getting past the wait for child line.
Here it is:

local success, hrootPos = pcall(function()
			return char:WaitForChild("HumanoidRootPart", 10).Position
		end)
		
		if success then
                   -- do script
        end

You can do two things:

Simpler:

local players = game:GetService("Players")

players.PlayerAdded:Connect(function(player)
	player.CharacterRemoving:Connect(function()
		local rootpart = player.Character:FindFirstChild("HumanoidRootPart")
		if not rootpart then print("too late to check position") return end
		local position = rootpart.CFrame
		-- or rootpart.Position whichever you prefer
	end)
end)

This completely new approach below means that your code will log the rootpart’s position every 2 seconds. Even if the rootpart is destroyed, its last position is stored in the player(not character since the character is constantly changing)

local rootpartcheck = coroutine.create(function()
	while true do
		task.wait(2)
		for i, player in players:GetPlayers() do
			local rootpos = player:FindFirstChild("rootpartpos")
			if not rootpos then continue end
			local character = player.Character
			if not character then continue end
			local rootpart = character:FindFirstChild("HumanoidRootPart")
			if not rootpart then continue end
			rootpos.Value = rootpart.CFrame
		end
	end
end) 

players.PlayerAdded:Connect(function(player)
	local rootpartpos = Instance.new("CFrameValue")
	rootpartpos.Name = "rootpartpos"
	rootpartpos.Parent = player
end)
1 Like

Thanks so much, so would I do this:

while task.wait(2) do
    for i, player in players:GetPlayers():
        rootpartcheck(player)
    end
end
game.Players.PlayerAdded:Connect(function(player)
    player:SetAttribute("LastPosition", CFrame.new(0, 1, 0))
    player.CharacterAdded:Connect(function(character)
        local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
        character:PivotTo(player:GetAttribute("LastPosition"))
        task.spawn(function()
            repeat task.wait(2)
                player:SetAttribute("LastPosition", humanoidRootPart:GetPivot())
            until character:FindFirstChildWhichIsA("Humanoid").Health <= 0
        end)
    end)
end)

If I’ve understood correctly your initial game design, you want to save the player’s last position every 2 seconds and when the player respawns, they teleport there.

1 Like

I’m creating a chunk generation algorithm and therefore need the player’s position, but the problem is the script stops. My script loops through all characters whenever it cannot find the specified character’s humanoidrootpart because their character is destroyed the script halts since it uses waitforchild and therefore can be exploited (for example, the exploiter could be destroying and undestroying the humanoidrootpart so the script would never carry on)

I need a loop that every 2 seconds checks every player’s position and does not effect other people’s loop/cause errors/warns if that humanoidrootpart doesn’t exist that is server-side.

Do you know of any solutions?

Ah, simple enough I suppose.
Try this:

local function checkForHRPs()
    for _, player in game.Players:GetPlayers() do
        task.spawn(function()
            if not player.Character then warn(string.format("%s does not have a character! Skipping loop for %s...", player.Name)) continue end
            if not player.Character:FindFirstChild("HumanoidRootPart") then warn(string.format("%s does not have a HumanoidRootPart though has a character!", player.Name)) continue end
            local HRP = player.Character.HumanoidRootPart
            print(string.format("%s is healthy!\nX: %d\nY: %d\nZ: %d", player.Name, HRP.CFrame.X, HRP.CFrame.Y, HRP.CFrame.Z))
        end)
    end
end

while task.wait(2) do
    checkForHRPs()
end

No you would put(underneath all the code)

coroutine.resume(rootpartcheck), sorry, I was conducting a coding lesson.

1 Like