function buildAttachmentMap(z)local c={}for z,I in pairs(z:GetChildren())do if I:IsA("\066\097\115\101\080\097\114\116")then for z,I in pairs(I:GetChildren())do if I:IsA("\065\116\116\097\099\104\109\101\110\116")then local z=I.Name:match("\094\040\046\043\041\082\105\103\065\116\116\097\099\104\109\101\110\116\036")local u=z and I.Parent:FindFirstChild(z)or nil if u then c[I.Name]={Joint=u,Attachment0=u.Part0[I.Name],Attachment1=u.Part1[I.Name]}end end end end end return c end return function(z)local c=z:FindFirstChild("\072\117\109\097\110\111\105\100")c.BreakJointsOnDeath=false local I=z:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if I then I.CanCollide=false end local u=buildAttachmentMap(z)local F=buildConstraints(u)local P=buildCollisionFilters(u,z.PrimaryPart)P.Parent=F F.Parent=z end
--[[
	 Builds a map that allows us to find Attachment0/Attachment1 when we have the other,
		and keep track of the joint that connects them. Format is
		{
			["WaistRigAttachment"] = {
				Joint = UpperTorso.Waist<Motor6D>,
				Attachment0 = LowerTorso.WaistRigAttachment<Attachment>,
				Attachment1 = UpperToros.WaistRigAttachment<Attachment>,
			},
			...
		}
--]]
function buildAttachmentMap(character)
	local attachmentMap = {}

	-- NOTE: GetConnectedParts doesn't work until parts have been parented to Workspace, so
	-- we can't use it (unless we want to have that silly restriction for creating ragdolls)
	for _, part in pairs(character:GetChildren()) do
		if part:IsA("BasePart") then
			for _, attachment in pairs(part:GetChildren()) do
				if attachment:IsA("Attachment") then
					local jointName = attachment.Name:match("^(.+)RigAttachment$")
					local joint = jointName and attachment.Parent:FindFirstChild(jointName) or nil

					if joint then
						attachmentMap[attachment.Name] = {
							Joint = joint,
							Attachment0 = joint.Part0[attachment.Name],
							Attachment1 = joint.Part1[attachment.Name],
						}
					end
				end
			end
		end
	end

	return attachmentMap
end

return function(character)
	local humanoid = character:FindFirstChild("Humanoid")
	-- Trying to recover from broken joints is not fun. It's impossible to reattach things like
	-- armor and tools in a generic way that works across all games, so we just prevent that
	-- from happening in the first place.
	humanoid.BreakJointsOnDeath = false

	-- Roblox decided to make the ghost HumanoidRootPart CanCollide=true for some reason, so
	-- we correct this and disable collisions. This prevents the invisible part from colliding
	-- with the world and ruining the physics simulation (e.g preventing a roundish torso from
	-- rolling)
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if rootPart then
		rootPart.CanCollide = false
	end

	local attachmentMap = buildAttachmentMap(character)
	local ragdollConstraints = buildConstraints(attachmentMap)
	local collisionFilters = buildCollisionFilters(attachmentMap, character.PrimaryPart)

	collisionFilters.Parent = ragdollConstraints
	ragdollConstraints.Parent = character
end
