--[=[ @class RagdollCollisionUtils ]=] local require = require(script.Parent.loader).load(script) local EnumUtils = require("EnumUtils") local RxBrioUtils = require("RxBrioUtils") local RxR15Utils = require("RxR15Utils") local Maid = require("Maid") local RagdollCollisionUtils = {} local R15_NO_COLLIDES = { {"LowerTorso", "LeftUpperArm"}, {"LeftUpperArm", "LeftHand"}, {"LowerTorso", "RightUpperArm"}, {"RightUpperArm", "RightHand"}, {"LeftUpperLeg", "RightUpperLeg"}, {"UpperTorso", "RightUpperLeg"}, {"RightUpperLeg", "RightFoot"}, {"UpperTorso", "LeftUpperLeg"}, {"LeftUpperLeg", "LeftFoot"}, -- Support weird R15 rigs {"UpperTorso", "LeftLowerLeg"}, {"UpperTorso", "RightLowerLeg"}, {"LowerTorso", "LeftLowerLeg"}, {"LowerTorso", "RightLowerLeg"}, {"UpperTorso", "LeftLowerArm"}, {"UpperTorso", "RightLowerArm"}, {"Head", "LeftUpperArm"}, {"Head", "RightUpperArm"}, -- Basically every other part {"HumanoidRootPart", "LeftUpperArm"}, {"HumanoidRootPart", "RightUpperArm"}, {"HumanoidRootPart", "LeftLowerArm"}, {"HumanoidRootPart", "RightLowerArm"}, {"HumanoidRootPart", "LeftLowerLeg"}, {"HumanoidRootPart", "RightLowerLeg"}, {"HumanoidRootPart", "LeftUpperLeg"}, {"HumanoidRootPart", "RightUpperLeg"}, {"HumanoidRootPart", "Head"}, {"HumanoidRootPart", "LeftFoot"}, {"HumanoidRootPart", "RightFoot"}, {"HumanoidRootPart", "LeftHand"}, {"HumanoidRootPart", "RightHand"}, {"HumanoidRootPart", "UpperTorso"}, {"HumanoidRootPart", "LowerTorso"}, } local R15_PARTS = { "LeftUpperArm"; "RightUpperArm"; "LeftLowerArm"; "RightLowerArm"; "LeftLowerLeg"; "RightLowerLeg"; "LeftUpperLeg"; "RightUpperLeg"; "Head"; "LeftFoot"; "RightFoot"; "LeftHand"; "RightHand"; "UpperTorso"; "LowerTorso"; } local R6_NO_COLLIDES = { {"Left Leg", "Right Leg"}, {"Head", "Right Arm"}, {"Head", "Left Arm"}, {"HumanoidRootPart", "Head"}, {"HumanoidRootPart", "Right Leg"}, {"HumanoidRootPart", "Right Arm"}, {"HumanoidRootPart", "Left Leg"}, {"HumanoidRootPart", "Left Arm"}, } function RagdollCollisionUtils.getCollisionData(rigType: Enum.HumanoidRigType) if rigType == Enum.HumanoidRigType.R15 then return R15_NO_COLLIDES elseif rigType == Enum.HumanoidRigType.R6 then return R6_NO_COLLIDES else error(string.format("[RagdollCollisionUtils] - Unknown rigType %q", tostring(rigType))) end end function RagdollCollisionUtils.preventCollisionAmongOthers(character: Model, part: BasePart) local topMaid = Maid.new() for _, partName in R15_PARTS do topMaid:GiveTask(RxR15Utils.observeCharacterPartBrio(character, partName):Subscribe(function(brio) if brio:IsDead() then return end local maid = brio:ToMaid() local foundPart = brio:GetValue() local noCollide = Instance.new("NoCollisionConstraint") noCollide.Name = "RagdollNoCollisionConstraint_Animating" noCollide.Part0 = part noCollide.Part1 = foundPart noCollide.Parent = part maid:GiveTask(noCollide) end)) end return topMaid end function RagdollCollisionUtils.ensureNoCollides(character: Model, rigType: Enum.HumanoidRigType) assert(typeof(character) == "Instance" and character:IsA("Model"), "Bad character") assert(EnumUtils.isOfType(Enum.HumanoidRigType, rigType), "Bad rigType") local topMaid = Maid.new() for _, data in RagdollCollisionUtils.getCollisionData(rigType) do local part0Name, part1Name = unpack(data) local observable = RxBrioUtils.flatCombineLatest({ part0 = RxR15Utils.observeCharacterPartBrio(character, part0Name); part1 = RxR15Utils.observeCharacterPartBrio(character, part1Name); }) topMaid:GiveTask(observable:Subscribe(function(state) if state.part0 and state.part1 then local maid = Maid.new() local noCollide = Instance.new("NoCollisionConstraint") noCollide.Name = "RagdollNoCollisionConstraint" noCollide.Part0 = state.part0 noCollide.Part1 = state.part1 noCollide.Parent = state.part1 maid:GiveTask(noCollide) topMaid[data] = maid else topMaid[data] = nil end end)) end return topMaid end return RagdollCollisionUtils