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’?
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.
Still get a warning which stops the script Infinite yield possible on 'Workspace.Omnomc:WaitForChild("HumanoidRootPart")'
local success, hrootPos = pcall(function()
return char:WaitForChild("HumanoidRootPart").Position
end)
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
.
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:(
A few things I want to clear up in this conversation:
-
Don’t assume
HumanoidRootPart
will always exist.
Technically,CharacterAdded
will fire and guarantees all theHumanoid
and it’s limbs will exist, but when referencing a character, there is a possibility theHumanoidRootPart
will be gone (like falling off the map). -
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 totrue
and you are spawned in when the code runs? - If this is set to false, the player will not respawn, therefore not updating theCharacter
property. - Is your
HumanoidRootPart
being renamed somehow? - Check the explorer window to see ifHumanoidRootPart
actually exists. - Are you using a custom character model? - You may not have a part called
HumanoidRootPart
.
- 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 withHumanoidRootPart
s, 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
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)
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
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.
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)
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.
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.