R15 rigs occasionally dying when replacing body parts

I am trying to swap out all body parts of an R15 rig. The problem is that intermittently the character dies. You can reproduce this by opening the following place in Studio, clicking Play, and waiting a few minutes

r15-dying-repro.rbxl (18.2 KB)

Here is my code:

local player = game:GetService("Players").PlayerAdded:Wait()
function applyBodyPart(character, r15Parts)
    local humanoid = character:FindFirstChild("Humanoid")
	local accoutrements = {}
	for _, child in pairs(character:GetChildren()) do
		if child:IsA("Accoutrement") then
			child.Parent = nil
			table.insert(accoutrements, child)
		end
	end
    for _, part in pairs(r15Parts) do
        local oldPart = character:FindFirstChild(part.Name)
        oldPart:Destroy()
        part:Clone().Parent = character
    end
	character.Humanoid:BuildRigFromAttachments()
	for _, accoutrement in pairs(accoutrements) do
		accoutrement.Parent = character
	end

end

player.CharacterAdded:connect(function(character)
	while character:FindFirstChild("Humanoid") and character.Humanoid.Health > 0 do
		wait(2)
		local r15Parts = game:GetService("ServerStorage"):FindFirstChild("R15")
		applyBodyPart(character, r15Parts:GetChildren())
	end
	error("DIED")
end)

Inside of ServerStorage I have a model called R15 which contains all the body parts for the character.

image

  • Edited to remove the line anchoring the HumanoidRootPart, as that was not necessary to repro
1 Like

Could you try disabling the Dead state on the humanoid before disconnecting any joints? (specifically the Neck)

humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, false)

then you can just re-enable it once your conversion is completed… I believe I’ve gotten around your issue by doing this before - I could be remembering incorrectly.

Do I need to disable the dead state on both client and server?

I believe :SetStateEnabled replicates to the server if you were to call it from the client (also, the documentation on it does not state it does not replicate, as it normally would), however given your examples you are calling it on the server so it should replicate through regardless.

I’d say you’re safe just calling it from the server directly before this loop:

humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, false)

-- your loop inside of applyBodyPart()
for _, part in pairs(r15Parts) do
    local oldPart = character:FindFirstChild(part.Name)
    oldPart:Destroy()
    part:Clone().Parent = character
end

humanoid:SetStateEnabled(Enum.HumanoidStateType.Dead, true)

again, I didn’t edit your repro and test, I could be totally wrong!

Isn’t there a function under humanoid now for replacing R15 body parts? It would probably be better to use that instead of BuildRigFromAttachments for this, though I have never tried it out myself.

If the function works how I think it does, then there should be no need to go through the process of disabling the dead state.

Extuls is right; Humanoid/ReplaceBodyPartR15

I did not know about this function and would probably be the more correct method of doing this.

Last time I checked it wasn’t enabled; is this still the case?

That method is not yet enabled.

2 Likes

Toggling the dead state immediately before and after the operation is not enough - the character still dies. I’m guessing the death is only detected at the next physics step or something like that. Still looking for solutions.

1 Like

In my game I have BuildRigFromAttachments() inside the for loop, so it rebuilds after each part is replaced. I remember having this problem but haven’t noticed it in a while, and i just did some testing and wasn’t able to trigger the death. I still think it happens with lag though but can’t test it.

Check out this thread. It might still be relevant.

2 Likes

Consider also reparenting the character’s humanoid to nil and back while you’re doing the swap. This stupid trick saved me back in 2010 and I think I’m still using it.

1 Like

You can swap all parts you want to replace after using SetStateEnabled and call Humanoid:BuildRigFromAttachments() afterwards. Then reenable the death state.

https://www.robloxdev.com/api-reference/function/Humanoid/BuildRigFromAttachments

This worked for me.

You might have already found a way to do this or forgotten about this issue, but I will say my solution here because I didn’t find it anywhere else: set Humanoid.RequiresNeck = false while you are doing the replacement. I have set so my characters never require a neck just to be sure, but I think it should be enough.