Ah I see what you mean. It’s a large difference on that scale but it’s likely Roblox is just doing some background work, and in the grand scheme of things it shouldn’t affect much, no?
function doSomethingIfEquipped()
if char:FindFirstChild("Tool") then
print("Doing something!")
end
end
hum:EquipTool(tool)
doSomethingIfEquipped() -- I expected this to work
What’s strange is that this does not have the same effect:
Code:
task.wait(3) -- Wait for player to load in
local tool = Instance.new("Tool")
local player = game.Players:GetPlayers()[1]
local hum = player.Character.Humanoid
local function customEquipTool(tool)
hum:UnequipTools() -- Roblox API says that this is what normally happens first when you do `hum:EquipTool()`
tool.Parent = player.Character
end
tool.Parent = player.Backpack
customEquipTool(tool)
print("from backpack")
local s = os.clock()
player.Character:WaitForChild(tool.Name)
print(os.clock()-s, "seconds to equip")
print()
tool.Parent = workspace
customEquipTool(tool)
print("from workspace")
local s = os.clock()
player.Character:WaitForChild(tool.Name)
print(os.clock()-s, "seconds to equip")
print()
tool.Parent = player.Backpack
customEquipTool(tool)
print("from backpack")
local s = os.clock()
player.Character:WaitForChild(tool.Name)
print(os.clock()-s, "seconds to equip")
print()
tool.Parent = workspace
customEquipTool(tool)
print("from workspace")
local s = os.clock()
player.Character:WaitForChild(tool.Name)
print(os.clock()-s, "seconds to equip")
Output:
from backpack
0.000008999952115118504 seconds to equip
from workspace
0.000004299916326999664 seconds to equip
from backpack
0.000005299923941493034 seconds to equip
from workspace
0.000002900022082030773 seconds to equip
So that’s what makes me think something funky is going on.
The reason this happens is because of how EquipTool calls are handled on the server when a Player and Backpack are involved.
If the Tool is in the Player’s Backpack, calling EquipTool from the server sends a message to the client to equip the Tool, to sort of mock the equip action being user-initiated.
I don’t remember what the reasoning was for needing to use EquipTool in place of just parenting the Tool directly to the character, but I assume there was some sort of buggy networking behavior at the time, and making the client take the action was the most stable way to work around this.
TL;DR - This is weird legacy shenanigans. You should avoid writing code that directly traverses through the children of an unknown object at runtime anyway. Doing so is unsafe and can lead to errors like this.
Couldn’t you just use :WaitForChild() with a short timeout instead?
Not perfect but better than nothing. That or yield until EquipTool is guaranteed to have run, somehow (If it doesn’t yield by default.)
The reason I need it is because my library attaches a motor6d between the tool & rig after equipped, and I expected that I could equip the tool and then run this function afterwards.
The fact that it works from workspace is even worse. It’s inconsistent. I was happy until I discovered that it didn’t work only when the tool got equipped after being unequipped (with the tool starting in workspace).
Is it reasonable to expect that hum:EquipTool() would parent the tool to the character synchronously? If so, I think this is bug-like behavior that needs to be addressed.
Not necessarily an unreasonable assumption, but I concur there’s a better/safer approach. You should be passing a strong reference to both the Tool you’re going to be equipping, and the character it’ll be equipped onto, directly to whatever function is creating the Motor6D joint. That way it doesn’t matter what the Tool’s parent is in that immediate moment.