function buildAttachmentMap(G)local E={}for G,x in pairs(G:GetChildren())do if x:IsA("\066\097\115\101\080\097\114\116")then for G,x in pairs(x:GetChildren())do if x:IsA("\065\116\116\097\099\104\109\101\110\116")then local G=x.Name:match("\094\040\046\043\041\082\105\103\065\116\116\097\099\104\109\101\110\116\036")local S=G and x.Parent:FindFirstChild(G)or nil if S then E[x.Name]={Joint=S,Attachment0=S.Part0[x.Name],Attachment1=S.Part1[x.Name]}end end end end end return E end return function(G)local E=G.Parent G.BreakJointsOnDeath=false local x=E:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if x then x.CanCollide=false end local S=game.Players:GetPlayerFromCharacter(E)local w=buildAttachmentMap(E)local s=buildConstraints(w)local k=buildCollisionFilters(w,E.PrimaryPart)k.Parent=s s.Parent=E;(game:GetService("\067\111\108\108\101\099\116\105\111\110\083\101\114\118\105\099\101")):AddTag(G,"\082\097\103\100\111\108\108")end

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(humanoid)
	local character = humanoid.Parent
	
	-- 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 player = game.Players:GetPlayerFromCharacter(character)

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

	collisionFilters.Parent = ragdollConstraints
	ragdollConstraints.Parent = character
	
	game:GetService("CollectionService"):AddTag(humanoid, "Ragdoll")
end
